0.0.0
This commit is contained in:
parent
f04221bbec
commit
0a43161b86
5 changed files with 185 additions and 0 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -25,3 +25,5 @@ doc/api/
|
||||||
# Don't commit pubspec lock file
|
# Don't commit pubspec lock file
|
||||||
# (Library packages only! Remove pattern if developing an application package)
|
# (Library packages only! Remove pattern if developing an application package)
|
||||||
pubspec.lock
|
pubspec.lock
|
||||||
|
|
||||||
|
log.txt
|
|
@ -1,2 +1,4 @@
|
||||||
# auth_oauth2
|
# auth_oauth2
|
||||||
|
[![version 0.0.0](https://img.shields.io/badge/pub-v0.0.0-red.svg)](https://pub.dartlang.org/packages/angel_auth_oauth2)
|
||||||
|
|
||||||
angel_auth strategy for OAuth2 login, i.e. Facebook.
|
angel_auth strategy for OAuth2 login, i.e. Facebook.
|
||||||
|
|
54
example/basic.dart
Normal file
54
example/basic.dart
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:angel_auth/angel_auth.dart';
|
||||||
|
import 'package:angel_diagnostics/angel_diagnostics.dart';
|
||||||
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
|
import 'package:angel_auth_oauth2/angel_auth_oauth2.dart';
|
||||||
|
import 'package:oauth2/oauth2.dart' as oauth2;
|
||||||
|
|
||||||
|
const Map<String, String> OAUTH2_CONFIG = const {
|
||||||
|
'callback': '<callback-url>',
|
||||||
|
'key': '<client-id>',
|
||||||
|
'secret': '<my-secret>',
|
||||||
|
'authorizationEndpoint': '<auth-url>',
|
||||||
|
'tokenEndpoint': '<token-url>'
|
||||||
|
};
|
||||||
|
|
||||||
|
main() async {
|
||||||
|
var app = new Angel()..use('/users', new MemoryService<User>());
|
||||||
|
|
||||||
|
var auth = new AngelAuth(jwtKey: 'oauth2 example secret', allowCookie: false);
|
||||||
|
auth.deserializer =
|
||||||
|
(String idStr) => app.service('users').read(int.parse(idStr));
|
||||||
|
auth.serializer = (User user) async => user.id;
|
||||||
|
|
||||||
|
auth.strategies.add(new OAuth2Strategy('example_site', OAUTH2_CONFIG,
|
||||||
|
(oauth2.Client client) async {
|
||||||
|
var response = await client.get('/link/to/user/profile');
|
||||||
|
return JSON.decode(response.body);
|
||||||
|
}));
|
||||||
|
|
||||||
|
app.get('/auth/example_site', auth.authenticate('example_site'));
|
||||||
|
app.get(
|
||||||
|
'/auth/example_site/callback',
|
||||||
|
auth.authenticate('example_site',
|
||||||
|
new AngelAuthOptions(callback: (req, res, jwt) async {
|
||||||
|
// In real-life, you might include a pop-up callback script
|
||||||
|
res.write('Your JWT: $jwt');
|
||||||
|
})));
|
||||||
|
|
||||||
|
await app.configure(auth);
|
||||||
|
await app.configure(logRequests(new File('log.txt')));
|
||||||
|
await app.configure(profileRequests());
|
||||||
|
|
||||||
|
var server = await app.startServer(InternetAddress.LOOPBACK_IP_V4, 3000);
|
||||||
|
print('Listening on http://${server.address.address}:${server.port}');
|
||||||
|
}
|
||||||
|
|
||||||
|
class User extends MemoryModel {
|
||||||
|
String example_siteId;
|
||||||
|
|
||||||
|
User({int id, this.example_siteId}) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
114
lib/angel_auth_oauth2.dart
Normal file
114
lib/angel_auth_oauth2.dart
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
library angel_auth_oauth2;
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:angel_auth/angel_auth.dart';
|
||||||
|
import 'package:angel_framework/src/http/response_context.dart';
|
||||||
|
import 'package:angel_framework/src/http/request_context.dart';
|
||||||
|
import 'package:angel_validate/angel_validate.dart';
|
||||||
|
import 'package:oauth2/oauth2.dart' as oauth2;
|
||||||
|
|
||||||
|
/// Loads a user profile via OAuth2.
|
||||||
|
typedef Future ProfileLoader(oauth2.Client client);
|
||||||
|
|
||||||
|
final Validator OAUTH2_OPTIONS_SCHEMA = new Validator({
|
||||||
|
'key*': isString,
|
||||||
|
'secret*': isString,
|
||||||
|
'authorizationEndpoint*': isString,
|
||||||
|
'tokenEndpoint*': isString,
|
||||||
|
'callback*': isString,
|
||||||
|
'scopes': new isInstanceOf<Iterable<String>>()
|
||||||
|
}, defaultValues: {
|
||||||
|
'scopes': <String>[]
|
||||||
|
}, customErrorMessages: {
|
||||||
|
'scopes': "'scopes' must be an Iterable of strings. You provided: {{value}}"
|
||||||
|
});
|
||||||
|
|
||||||
|
class AngelAuthOauth2Options {
|
||||||
|
String key, secret, authorizationEndpoint, tokenEndpoint, callback;
|
||||||
|
Iterable<String> scopes;
|
||||||
|
|
||||||
|
AngelAuthOauth2Options(
|
||||||
|
{this.key,
|
||||||
|
this.secret,
|
||||||
|
this.authorizationEndpoint,
|
||||||
|
this.tokenEndpoint,
|
||||||
|
this.callback,
|
||||||
|
Iterable<String> scopes: const []}) {
|
||||||
|
this.scopes = scopes ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
factory AngelAuthOauth2Options.fromJson(Map json) =>
|
||||||
|
new AngelAuthOauth2Options(
|
||||||
|
key: json['key'],
|
||||||
|
secret: json['secret'],
|
||||||
|
authorizationEndpoint: json['authorizationEndpoint'],
|
||||||
|
tokenEndpoint: json['tokenEndpoint'],
|
||||||
|
callback: json['callback'],
|
||||||
|
scopes: json['scopes'] ?? <String>[]);
|
||||||
|
|
||||||
|
Map<String, String> toJson() {
|
||||||
|
return {
|
||||||
|
'key': key,
|
||||||
|
'secret': secret,
|
||||||
|
'authorizationEndpoint': authorizationEndpoint,
|
||||||
|
'tokenEndpoint': tokenEndpoint,
|
||||||
|
'callback': callback,
|
||||||
|
'scopes': scopes.toList()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OAuth2Strategy implements AuthStrategy {
|
||||||
|
String _name;
|
||||||
|
AngelAuthOauth2Options _options;
|
||||||
|
final ProfileLoader profileLoader;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get name => _name;
|
||||||
|
|
||||||
|
@override
|
||||||
|
set name(String value) => _name = name;
|
||||||
|
|
||||||
|
/// [options] can be either a `Map` or an instance of [AngelAuthOauth2Options].
|
||||||
|
OAuth2Strategy(this._name, options, this.profileLoader) {
|
||||||
|
if (options is AngelAuthOauth2Options)
|
||||||
|
_options = options;
|
||||||
|
else if (options is Map)
|
||||||
|
_options = new AngelAuthOauth2Options.fromJson(
|
||||||
|
OAUTH2_OPTIONS_SCHEMA.enforce(options));
|
||||||
|
else
|
||||||
|
throw new ArgumentError('Invalid OAuth2 options: $options');
|
||||||
|
}
|
||||||
|
|
||||||
|
oauth2.AuthorizationCodeGrant createGrant() =>
|
||||||
|
new oauth2.AuthorizationCodeGrant(
|
||||||
|
_options.key,
|
||||||
|
Uri.parse(_options.authorizationEndpoint),
|
||||||
|
Uri.parse(_options.tokenEndpoint),
|
||||||
|
secret: _options.secret);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future authenticate(RequestContext req, ResponseContext res,
|
||||||
|
[AngelAuthOptions options]) async {
|
||||||
|
if (options != null) return authenticateCallback(req, res, options);
|
||||||
|
|
||||||
|
var grant = createGrant();
|
||||||
|
res.redirect(grant
|
||||||
|
.getAuthorizationUrl(Uri.parse(_options.callback),
|
||||||
|
scopes: _options.scopes)
|
||||||
|
.toString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future authenticateCallback(RequestContext req, ResponseContext res,
|
||||||
|
[AngelAuthOptions options]) async {
|
||||||
|
var grant = createGrant();
|
||||||
|
await grant.getAuthorizationUrl(Uri.parse(_options.callback),
|
||||||
|
scopes: _options.scopes);
|
||||||
|
var client = await grant.handleAuthorizationResponse(req.query);
|
||||||
|
return await profileLoader(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> canLogout(RequestContext req, ResponseContext res) async => true;
|
||||||
|
}
|
13
pubspec.yaml
Normal file
13
pubspec.yaml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
name: angel_auth_oauth2
|
||||||
|
description: angel_auth strategy for OAuth2 login, i.e. Facebook.
|
||||||
|
version: 0.0.0
|
||||||
|
author: Tobe O <thosakwe@gmail.com>
|
||||||
|
environment:
|
||||||
|
sdk: ">=1.19.0"
|
||||||
|
homepage: https://github.com/angel-dart/auth_oauth2.git
|
||||||
|
dependencies:
|
||||||
|
angel_auth: ^1.0.0-dev
|
||||||
|
angel_validate: ^1.0.0-beta
|
||||||
|
oauth2: ^1.0.0
|
||||||
|
dev_dependencies:
|
||||||
|
angel_diagnostics: ^1.0.0-dev
|
Loading…
Reference in a new issue