2.0.0
This commit is contained in:
parent
5056738ef4
commit
3a5a31c5de
6 changed files with 58 additions and 54 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -71,3 +71,5 @@ com_crashlytics_export_strings.xml
|
||||||
crashlytics.properties
|
crashlytics.properties
|
||||||
crashlytics-build.properties
|
crashlytics-build.properties
|
||||||
fabric.properties
|
fabric.properties
|
||||||
|
|
||||||
|
.dart_tool
|
|
@ -75,7 +75,7 @@ a popup window. In this case, use `confirmPopupAuthentication`, which is bundled
|
||||||
configureServer(Angel app) async {
|
configureServer(Angel app) async {
|
||||||
// ...
|
// ...
|
||||||
var auth = new AngelAuth();
|
var auth = new AngelAuth();
|
||||||
auth.strategies.add(oauth2Strategy);
|
auth.strategies['github'] = oauth2Strategy;
|
||||||
|
|
||||||
// Redirect
|
// Redirect
|
||||||
app.get('/auth/github', auth.authenticate('github'));
|
app.get('/auth/github', auth.authenticate('github'));
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
analyzer:
|
analyzer:
|
||||||
strong-mode: true
|
strong-mode:
|
||||||
|
implicit-casts: false
|
|
@ -2,7 +2,6 @@ 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_framework/angel_framework.dart';
|
import 'package:angel_framework/angel_framework.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:logging/logging.dart';
|
||||||
import 'package:oauth2/oauth2.dart' as oauth2;
|
import 'package:oauth2/oauth2.dart' as oauth2;
|
||||||
|
@ -17,29 +16,31 @@ final AngelAuthOAuth2Options oAuth2Config = new AngelAuthOAuth2Options(
|
||||||
if (contentType.type == 'application') {
|
if (contentType.type == 'application') {
|
||||||
if (contentType.subtype == 'x-www-form-urlencoded')
|
if (contentType.subtype == 'x-www-form-urlencoded')
|
||||||
return Uri.splitQueryString(body);
|
return Uri.splitQueryString(body);
|
||||||
else if (contentType.subtype == 'json') return JSON.decode(body);
|
else if (contentType.subtype == 'json')
|
||||||
|
return (json.decode(body) as Map).cast<String, String>();
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new FormatException('Invalid content-type $contentType; expected application/x-www-form-urlencoded or application/json.');
|
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.use('/users', new MapService());
|
app.use('/users', new MapService());
|
||||||
|
|
||||||
var auth =
|
var auth =
|
||||||
new AngelAuth<User>(jwtKey: 'oauth2 example secret', allowCookie: false);
|
new AngelAuth<User>(jwtKey: 'oauth2 example secret', allowCookie: false);
|
||||||
|
|
||||||
auth.deserializer =
|
auth.deserializer =
|
||||||
(id) => app.service('users').read(id).then((u) => User.parse(u));
|
(id) => app.service('users').read(id).then((u) => User.parse(u as Map));
|
||||||
|
|
||||||
auth.serializer = (User user) async => user.id;
|
auth.serializer = (User user) async => user.id;
|
||||||
|
|
||||||
auth.strategies.add(
|
auth.strategies['github'] = new OAuth2Strategy(
|
||||||
new OAuth2Strategy('github', oAuth2Config, (oauth2.Client client) async {
|
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'];
|
||||||
|
|
||||||
Iterable<Map> matchingUsers = await app.service('users').index({
|
Iterable<Map> matchingUsers = await app.service('users').index({
|
||||||
|
@ -53,9 +54,10 @@ main() async {
|
||||||
// Otherwise,create a user
|
// Otherwise,create a user
|
||||||
return await app
|
return await app
|
||||||
.service('users')
|
.service('users')
|
||||||
.create({'githubId': id}).then((u) => User.parse(u));
|
.create({'githubId': id}).then((u) => User.parse(u as Map));
|
||||||
}
|
}
|
||||||
}));
|
},
|
||||||
|
);
|
||||||
|
|
||||||
app.get('/auth/github', auth.authenticate('github'));
|
app.get('/auth/github', auth.authenticate('github'));
|
||||||
app.get(
|
app.get(
|
||||||
|
@ -74,7 +76,7 @@ main() async {
|
||||||
app.logger = new Logger('angel')..onRecord.listen(print);
|
app.logger = new Logger('angel')..onRecord.listen(print);
|
||||||
|
|
||||||
var http = new AngelHttp(app);
|
var http = new AngelHttp(app);
|
||||||
var server = await http.startServer(InternetAddress.LOOPBACK_IP_V4, 3000);
|
var server = await http.startServer(InternetAddress.loopbackIPv4, 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');
|
||||||
|
@ -89,7 +91,7 @@ class User extends Model {
|
||||||
User({this.id, this.githubId});
|
User({this.id, this.githubId});
|
||||||
|
|
||||||
static User parse(Map map) =>
|
static User parse(Map map) =>
|
||||||
new User(id: map['id'], githubId: map['github_id']);
|
new User(id: map['id'] as String, githubId: map['github_id'] as int);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {'id': id, 'github_id': githubId};
|
Map<String, dynamic> toJson() => {'id': id, 'github_id': githubId};
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,10 @@ import 'package:oauth2/oauth2.dart' as oauth2;
|
||||||
final Validator OAUTH2_OPTIONS_SCHEMA = new Validator({
|
final Validator OAUTH2_OPTIONS_SCHEMA = new Validator({
|
||||||
'key*': isString,
|
'key*': isString,
|
||||||
'secret*': isString,
|
'secret*': isString,
|
||||||
'authorizationEndpoint*': anyOf(isString, const isInstanceOf<Uri>()),
|
'authorizationEndpoint*': anyOf(isString, const TypeMatcher<Uri>()),
|
||||||
'tokenEndpoint*': anyOf(isString, const isInstanceOf<Uri>()),
|
'tokenEndpoint*': anyOf(isString, const TypeMatcher<Uri>()),
|
||||||
'callback*': isString,
|
'callback*': isString,
|
||||||
'scopes': const isInstanceOf<Iterable<String>>()
|
'scopes': const TypeMatcher<Iterable<String>>()
|
||||||
}, defaultValues: {
|
}, defaultValues: {
|
||||||
'scopes': <String>[]
|
'scopes': <String>[]
|
||||||
}, customErrorMessages: {
|
}, customErrorMessages: {
|
||||||
|
@ -29,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 authorizationEndpoint;
|
final String authorizationEndpoint;
|
||||||
|
|
||||||
/// The remote endpoint that exchanges auth codes for access tokens.
|
/// The remote endpoint that exchanges auth codes for access tokens.
|
||||||
final tokenEndpoint;
|
final String 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;
|
||||||
|
@ -55,12 +55,13 @@ class AngelAuthOAuth2Options {
|
||||||
|
|
||||||
factory AngelAuthOAuth2Options.fromJson(Map json) =>
|
factory AngelAuthOAuth2Options.fromJson(Map json) =>
|
||||||
new AngelAuthOAuth2Options(
|
new AngelAuthOAuth2Options(
|
||||||
key: json['key'],
|
key: json['key'] as String,
|
||||||
secret: json['secret'],
|
secret: json['secret'] as String,
|
||||||
authorizationEndpoint: json['authorizationEndpoint'],
|
authorizationEndpoint: json['authorizationEndpoint'] as String,
|
||||||
tokenEndpoint: json['tokenEndpoint'],
|
tokenEndpoint: json['tokenEndpoint'] as String,
|
||||||
callback: json['callback'],
|
callback: json['callback'] as String,
|
||||||
scopes: json['scopes'] ?? <String>[]);
|
scopes: (json['scopes'] as Iterable)?.cast<String>()?.toList() ??
|
||||||
|
<String>[]);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {
|
||||||
|
@ -74,14 +75,13 @@ class AngelAuthOAuth2Options {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class OAuth2Strategy<T> implements AuthStrategy {
|
class OAuth2Strategy<User> implements AuthStrategy<User> {
|
||||||
final FutureOr<T> Function(oauth2.Client) verifier;
|
final FutureOr<User> Function(oauth2.Client) verifier;
|
||||||
String name;
|
|
||||||
|
|
||||||
AngelAuthOAuth2Options _options;
|
AngelAuthOAuth2Options _options;
|
||||||
|
|
||||||
/// [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(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)
|
||||||
|
@ -101,8 +101,8 @@ class OAuth2Strategy<T> implements AuthStrategy {
|
||||||
getParameters: _options.getParameters);
|
getParameters: _options.getParameters);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future authenticate(RequestContext req, ResponseContext res,
|
FutureOr<User> authenticate(RequestContext req, ResponseContext res,
|
||||||
[AngelAuthOptions options]) async {
|
[AngelAuthOptions<User> options]) async {
|
||||||
if (options != null) return authenticateCallback(req, res, options);
|
if (options != null) return authenticateCallback(req, res, options);
|
||||||
|
|
||||||
var grant = createGrant();
|
var grant = createGrant();
|
||||||
|
@ -110,18 +110,16 @@ class OAuth2Strategy<T> implements AuthStrategy {
|
||||||
.getAuthorizationUrl(Uri.parse(_options.callback),
|
.getAuthorizationUrl(Uri.parse(_options.callback),
|
||||||
scopes: _options.scopes)
|
scopes: _options.scopes)
|
||||||
.toString());
|
.toString());
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future authenticateCallback(RequestContext req, ResponseContext res,
|
Future<User> authenticateCallback(RequestContext req, ResponseContext res,
|
||||||
[AngelAuthOptions options]) async {
|
[AngelAuthOptions options]) async {
|
||||||
var grant = createGrant();
|
var grant = createGrant();
|
||||||
await grant.getAuthorizationUrl(Uri.parse(_options.callback),
|
await grant.getAuthorizationUrl(Uri.parse(_options.callback),
|
||||||
scopes: _options.scopes);
|
scopes: _options.scopes);
|
||||||
var client = await grant.handleAuthorizationResponse(req.query);
|
var client =
|
||||||
|
await grant.handleAuthorizationResponse(req.uri.queryParameters);
|
||||||
return await verifier(client);
|
return await verifier(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<bool> canLogout(RequestContext req, ResponseContext res) async => true;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
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.2
|
version: 2.0.0
|
||||||
author: Tobe O <thosakwe@gmail.com>
|
author: Tobe O <thosakwe@gmail.com>
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=1.19.0 <3.0.0"
|
sdk: ">=2.0.0-dev <3.0.0"
|
||||||
homepage: https://github.com/angel-dart/auth_oauth2.git
|
homepage: https://github.com/angel-dart/auth_oauth2.git
|
||||||
dependencies:
|
dependencies:
|
||||||
angel_auth: ^1.0.0-dev
|
angel_auth: ^2.0.0
|
||||||
angel_validate: ^1.0.0-beta
|
angel_framework: ^2.0.0-alpha
|
||||||
|
angel_validate: ^2.0.0-alpha
|
||||||
oauth2: ^1.0.0
|
oauth2: ^1.0.0
|
Loading…
Reference in a new issue