Added getParameters
This commit is contained in:
parent
3944a3f482
commit
ed3cb579ae
8 changed files with 73 additions and 43 deletions
|
@ -5,8 +5,6 @@
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/example/packages" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||||
</content>
|
</content>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Github Auth Server" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application" singleton="true">
|
<configuration default="false" name="Github Auth Server" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application" singleton="true">
|
||||||
<option name="filePath" value="$PROJECT_DIR$/example/github.dart" />
|
<option name="filePath" value="$PROJECT_DIR$/example/main.dart" />
|
||||||
<option name="workingDirectory" value="$PROJECT_DIR$" />
|
<option name="workingDirectory" value="$PROJECT_DIR$" />
|
||||||
<method />
|
<method />
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|
2
CHANGELOG.md
Normal file
2
CHANGELOG.md
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# 1.0.2
|
||||||
|
Added `getParameters` to `AngelOAuth2Options`.
|
28
README.md
28
README.md
|
@ -1,6 +1,6 @@
|
||||||
# auth_oauth2
|
# auth_oauth2
|
||||||
|
|
||||||
[![version 1.0.1](https://img.shields.io/badge/pub-1.0.1-brightgreen.svg)](https://pub.dartlang.org/packages/angel_auth_oauth2)
|
[![Pub](https://img.shields.io/pub/v/angel_auth_oauth2.svg)](https://pub.dartlang.org/packages/angel_auth_oauth2)
|
||||||
|
|
||||||
`package:angel_auth` strategy for OAuth2 login, i.e. Facebook or Github.
|
`package:angel_auth` strategy for OAuth2 login, i.e. Facebook or Github.
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ configureServer(Angel app) async {
|
||||||
var opts = new AngelOAuth2Options.fromJson(map);
|
var opts = new AngelOAuth2Options.fromJson(map);
|
||||||
|
|
||||||
// Create in-place:
|
// Create in-place:
|
||||||
const AngelAuthOAuth2Options OAUTH2_CONFIG = const AngelAuthOAuth2Options(
|
var opts = const AngelAuthOAuth2Options(
|
||||||
callback: '<callback-url>',
|
callback: '<callback-url>',
|
||||||
key: '<client-id>',
|
key: '<client-id>',
|
||||||
secret: '<client-secret>',
|
secret: '<client-secret>',
|
||||||
|
@ -98,9 +98,31 @@ you can add it in the `AngelOAuth2Options` constructor:
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
configureServer(Angel app) async {
|
configureServer(Angel app) async {
|
||||||
const AngelOAuth2Options OPTS = const AngelOAuth2Options(
|
var opts = const AngelOAuth2Options(
|
||||||
// ...
|
// ...
|
||||||
delimiter: ','
|
delimiter: ','
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Handling non-JSON responses
|
||||||
|
Many OAuth2 providers do not follow the specification, and do not return
|
||||||
|
`application/json` responses.
|
||||||
|
|
||||||
|
You can add a `getParameters` callback to parse the contents of any arbitrary
|
||||||
|
response:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
var opts = const AngelOAuth2Options(
|
||||||
|
// ...
|
||||||
|
getParameters: (contentType, body) {
|
||||||
|
if (contentType.type == 'application') {
|
||||||
|
if (contentType.subtype == 'x-www-form-urlencoded')
|
||||||
|
return Uri.splitQueryString(body);
|
||||||
|
else if (contentType.subtype == 'json') return JSON.decode(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FormatException('Invalid content-type $contentType; expected application/x-www-form-urlencoded or application/json.');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
```
|
|
@ -1,31 +1,43 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:angel_auth/angel_auth.dart';
|
import 'package:angel_auth/angel_auth.dart';
|
||||||
import 'package:angel_diagnostics/angel_diagnostics.dart';
|
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
import 'package:angel_framework/common.dart';
|
import 'package:angel_framework/common.dart';
|
||||||
import 'package:angel_auth_oauth2/angel_auth_oauth2.dart';
|
import 'package:angel_auth_oauth2/angel_auth_oauth2.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
import 'package:oauth2/oauth2.dart' as oauth2;
|
import 'package:oauth2/oauth2.dart' as oauth2;
|
||||||
|
|
||||||
const AngelAuthOAuth2Options OAUTH2_CONFIG = const AngelAuthOAuth2Options(
|
final AngelAuthOAuth2Options oAuth2Config = new AngelAuthOAuth2Options(
|
||||||
callback: 'http://localhost:3000/auth/github/callback',
|
callback: 'http://localhost:3000/auth/github/callback',
|
||||||
key: '6caeaf5d4c04936ec34f',
|
key: '6caeaf5d4c04936ec34f',
|
||||||
secret: '178360518cf9de4802e2346a4b6ebec525dc4427',
|
secret: '178360518cf9de4802e2346a4b6ebec525dc4427',
|
||||||
authorizationEndpoint: 'http://github.com/login/oauth/authorize',
|
authorizationEndpoint: 'http://github.com/login/oauth/authorize',
|
||||||
tokenEndpoint: 'https://github.com/login/oauth/access_token');
|
tokenEndpoint: 'https://github.com/login/oauth/access_token',
|
||||||
|
getParameters: (contentType, body) {
|
||||||
|
if (contentType.type == 'application') {
|
||||||
|
if (contentType.subtype == 'x-www-form-urlencoded')
|
||||||
|
return Uri.splitQueryString(body);
|
||||||
|
else if (contentType.subtype == 'json') return JSON.decode(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FormatException('Invalid content-type $contentType; expected application/x-www-form-urlencoded or application/json.');
|
||||||
|
});
|
||||||
|
|
||||||
main() async {
|
main() async {
|
||||||
var app = new Angel();
|
var app = new Angel();
|
||||||
app.lazyParseBodies = true;
|
app.lazyParseBodies = true;
|
||||||
app.use('/users', new MapService());
|
app.use('/users', new MapService());
|
||||||
|
|
||||||
var auth = new AngelAuth(jwtKey: 'oauth2 example secret', allowCookie: false);
|
var auth =
|
||||||
|
new AngelAuth<User>(jwtKey: 'oauth2 example secret', allowCookie: false);
|
||||||
|
|
||||||
|
auth.deserializer =
|
||||||
|
(id) => app.service('users').read(id).then((u) => User.parse(u));
|
||||||
|
|
||||||
auth.deserializer = app.service('users').read;
|
|
||||||
auth.serializer = (User user) async => user.id;
|
auth.serializer = (User user) async => user.id;
|
||||||
|
|
||||||
auth.strategies.add(
|
auth.strategies.add(
|
||||||
new OAuth2Strategy('github', OAUTH2_CONFIG, (oauth2.Client client) async {
|
new OAuth2Strategy('github', oAuth2Config, (oauth2.Client client) async {
|
||||||
var response = await client.get('https://api.github.com/user');
|
var response = await client.get('https://api.github.com/user');
|
||||||
var ghUser = JSON.decode(response.body);
|
var ghUser = JSON.decode(response.body);
|
||||||
var id = ghUser['id'];
|
var id = ghUser['id'];
|
||||||
|
@ -41,7 +53,7 @@ main() async {
|
||||||
// Otherwise,create a user
|
// Otherwise,create a user
|
||||||
return await app
|
return await app
|
||||||
.service('users')
|
.service('users')
|
||||||
.create({'githubId': id}).then(User.parse);
|
.create({'githubId': id}).then((u) => User.parse(u));
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -57,10 +69,12 @@ main() async {
|
||||||
res.write('Your JWT: $jwt');
|
res.write('Your JWT: $jwt');
|
||||||
})));
|
})));
|
||||||
|
|
||||||
await app.configure(auth);
|
await app.configure(auth.configureServer);
|
||||||
await app.configure(logRequests());
|
|
||||||
|
|
||||||
var server = await app.startServer(InternetAddress.LOOPBACK_IP_V4, 3000);
|
app.logger = new Logger('angel')..onRecord.listen(print);
|
||||||
|
|
||||||
|
var http = new AngelHttp(app);
|
||||||
|
var server = await http.startServer(InternetAddress.LOOPBACK_IP_V4, 3000);
|
||||||
var url = 'http://${server.address.address}:${server.port}';
|
var url = 'http://${server.address.address}:${server.port}';
|
||||||
print('Listening on $url');
|
print('Listening on $url');
|
||||||
print('View user listing: $url/users');
|
print('View user listing: $url/users');
|
|
@ -2,21 +2,18 @@ library angel_auth_oauth2;
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:angel_auth/angel_auth.dart';
|
import 'package:angel_auth/angel_auth.dart';
|
||||||
import 'package:angel_framework/src/http/response_context.dart';
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
import 'package:angel_framework/src/http/request_context.dart';
|
|
||||||
import 'package:angel_validate/angel_validate.dart';
|
import 'package:angel_validate/angel_validate.dart';
|
||||||
|
import 'package:http_parser/http_parser.dart';
|
||||||
import 'package:oauth2/oauth2.dart' as oauth2;
|
import 'package:oauth2/oauth2.dart' as oauth2;
|
||||||
|
|
||||||
/// Loads a user profile via OAuth2.
|
|
||||||
typedef Future OAuth2Verifier(oauth2.Client client);
|
|
||||||
|
|
||||||
final Validator OAUTH2_OPTIONS_SCHEMA = new Validator({
|
final Validator OAUTH2_OPTIONS_SCHEMA = new Validator({
|
||||||
'key*': isString,
|
'key*': isString,
|
||||||
'secret*': isString,
|
'secret*': isString,
|
||||||
'authorizationEndpoint*': isString,
|
'authorizationEndpoint*': anyOf(isString, const isInstanceOf<Uri>()),
|
||||||
'tokenEndpoint*': isString,
|
'tokenEndpoint*': anyOf(isString, const isInstanceOf<Uri>()),
|
||||||
'callback*': isString,
|
'callback*': isString,
|
||||||
'scopes': new isInstanceOf<Iterable<String>>()
|
'scopes': const isInstanceOf<Iterable<String>>()
|
||||||
}, defaultValues: {
|
}, defaultValues: {
|
||||||
'scopes': <String>[]
|
'scopes': <String>[]
|
||||||
}, customErrorMessages: {
|
}, customErrorMessages: {
|
||||||
|
@ -32,10 +29,10 @@ class AngelAuthOAuth2Options {
|
||||||
final String secret;
|
final String secret;
|
||||||
|
|
||||||
/// The remote endpoint that prompts external users for authentication credentials.
|
/// The remote endpoint that prompts external users for authentication credentials.
|
||||||
final String authorizationEndpoint;
|
final authorizationEndpoint;
|
||||||
|
|
||||||
/// The remote endpoint that exchanges auth codes for access tokens.
|
/// The remote endpoint that exchanges auth codes for access tokens.
|
||||||
final String tokenEndpoint;
|
final tokenEndpoint;
|
||||||
|
|
||||||
/// The callback URL that the OAuth2 server should redirect authenticated users to.
|
/// The callback URL that the OAuth2 server should redirect authenticated users to.
|
||||||
final String callback;
|
final String callback;
|
||||||
|
@ -44,6 +41,8 @@ class AngelAuthOAuth2Options {
|
||||||
final String delimiter;
|
final String delimiter;
|
||||||
final Iterable<String> scopes;
|
final Iterable<String> scopes;
|
||||||
|
|
||||||
|
final Map<String, String> Function(MediaType, String) getParameters;
|
||||||
|
|
||||||
const AngelAuthOAuth2Options(
|
const AngelAuthOAuth2Options(
|
||||||
{this.key,
|
{this.key,
|
||||||
this.secret,
|
this.secret,
|
||||||
|
@ -51,7 +50,8 @@ class AngelAuthOAuth2Options {
|
||||||
this.tokenEndpoint,
|
this.tokenEndpoint,
|
||||||
this.callback,
|
this.callback,
|
||||||
this.delimiter: ' ',
|
this.delimiter: ' ',
|
||||||
this.scopes: const []});
|
this.scopes: const [],
|
||||||
|
this.getParameters});
|
||||||
|
|
||||||
factory AngelAuthOAuth2Options.fromJson(Map json) =>
|
factory AngelAuthOAuth2Options.fromJson(Map json) =>
|
||||||
new AngelAuthOAuth2Options(
|
new AngelAuthOAuth2Options(
|
||||||
|
@ -62,7 +62,7 @@ class AngelAuthOAuth2Options {
|
||||||
callback: json['callback'],
|
callback: json['callback'],
|
||||||
scopes: json['scopes'] ?? <String>[]);
|
scopes: json['scopes'] ?? <String>[]);
|
||||||
|
|
||||||
Map<String, String> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {
|
||||||
'key': key,
|
'key': key,
|
||||||
'secret': secret,
|
'secret': secret,
|
||||||
|
@ -74,19 +74,14 @@ class AngelAuthOAuth2Options {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class OAuth2Strategy implements AuthStrategy {
|
class OAuth2Strategy<T> implements AuthStrategy {
|
||||||
String _name;
|
final FutureOr<T> Function(oauth2.Client) verifier;
|
||||||
|
String name;
|
||||||
|
|
||||||
AngelAuthOAuth2Options _options;
|
AngelAuthOAuth2Options _options;
|
||||||
final OAuth2Verifier verifier;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get name => _name;
|
|
||||||
|
|
||||||
@override
|
|
||||||
set name(String value) => _name = name;
|
|
||||||
|
|
||||||
/// [options] can be either a `Map` or an instance of [AngelAuthOAuth2Options].
|
/// [options] can be either a `Map` or an instance of [AngelAuthOAuth2Options].
|
||||||
OAuth2Strategy(this._name, options, this.verifier) {
|
OAuth2Strategy(this.name, options, this.verifier) {
|
||||||
if (options is AngelAuthOAuth2Options)
|
if (options is AngelAuthOAuth2Options)
|
||||||
_options = options;
|
_options = options;
|
||||||
else if (options is Map)
|
else if (options is Map)
|
||||||
|
@ -102,7 +97,8 @@ class OAuth2Strategy implements AuthStrategy {
|
||||||
Uri.parse(_options.authorizationEndpoint),
|
Uri.parse(_options.authorizationEndpoint),
|
||||||
Uri.parse(_options.tokenEndpoint),
|
Uri.parse(_options.tokenEndpoint),
|
||||||
secret: _options.secret,
|
secret: _options.secret,
|
||||||
delimiter: _options.delimiter ?? ' ');
|
delimiter: _options.delimiter ?? ' ',
|
||||||
|
getParameters: _options.getParameters);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future authenticate(RequestContext req, ResponseContext res,
|
Future authenticate(RequestContext req, ResponseContext res,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: angel_auth_oauth2
|
name: angel_auth_oauth2
|
||||||
description: angel_auth strategy for OAuth2 login, i.e. Facebook.
|
description: angel_auth strategy for OAuth2 login, i.e. Facebook.
|
||||||
version: 1.0.1
|
version: 1.0.2
|
||||||
author: Tobe O <thosakwe@gmail.com>
|
author: Tobe O <thosakwe@gmail.com>
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=1.19.0"
|
sdk: ">=1.19.0"
|
||||||
|
@ -9,5 +9,3 @@ dependencies:
|
||||||
angel_auth: ^1.0.0-dev
|
angel_auth: ^1.0.0-dev
|
||||||
angel_validate: ^1.0.0-beta
|
angel_validate: ^1.0.0-beta
|
||||||
oauth2: ^1.0.0
|
oauth2: ^1.0.0
|
||||||
dev_dependencies:
|
|
||||||
angel_diagnostics: ^1.0.0-dev
|
|
Loading…
Reference in a new issue