Update auth

This commit is contained in:
thomashii 2021-07-15 15:57:47 +08:00
parent 62336e0d53
commit fdc909b536
7 changed files with 41 additions and 40 deletions

View file

@ -20,7 +20,7 @@
* Migrated angel_validate to 4.0.0 (7/7 tests passed) * Migrated angel_validate to 4.0.0 (7/7 tests passed)
* Migrated json_god to 4.0.0 (13/13 tests passed) * Migrated json_god to 4.0.0 (13/13 tests passed)
* Migrated angel_client to 4.0.0 (13/13 tests passed) * Migrated angel_client to 4.0.0 (13/13 tests passed)
* Migrated angel_websocket to 4.0.0 (2/3 tests passed) * Migrated angel_websocket to 4.0.0 (3/3 tests passed)
* Migrated angel_test to 4.0.0 (1/1 test passed) * Migrated angel_test to 4.0.0 (1/1 test passed)
* Added symbol_table and migrated to 2.0.0 (16/16 tests passed) * Added symbol_table and migrated to 2.0.0 (16/16 tests passed)
* Migrated jael to 4.0.0 (20/20 tests passed) * Migrated jael to 4.0.0 (20/20 tests passed)

View file

@ -1,10 +1,15 @@
# Change Log # Change Log
## 4.0.5
* Added support for verifier function to return an empty Map instead of null
* Fixed `canRespondWithJson` option to return data in the reponse body when set to true
## 4.0.4 ## 4.0.4
* Changed `serializer` and `deserializer` parameters to be required * Changed `serializer` and `deserializer` parameters to be required
* Fixed HTTP basic authentication * Fixed HTTP basic authentication
* Passed all 51 unit tests * All 31 unit tests passed
## 4.0.3 ## 4.0.3

View file

@ -1,6 +1,6 @@
# Angel3 Anthentication # Angel3 Anthentication
[![version](https://img.shields.io/badge/pub-v4.0.4-brightgreen)](https://pub.dev/packages/angel3_auth) [![version](https://img.shields.io/badge/pub-v4.0.5-brightgreen)](https://pub.dev/packages/angel3_auth)
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety) [![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion) [![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
@ -52,9 +52,7 @@ configureServer(Angel app) async {
## Default Authentication Callback ## Default Authentication Callback
A frequent use case within SPA's is opening OAuth login endpoints in a separate window. A frequent use case within SPA's is opening OAuth login endpoints in a separate window. [`angel3_client`](https://github.com/dukefirehawk/angel/tree/angel3/packages/client) provides a facility for this, which works perfectly with the default callback provided in this package.
[`angel3_client`](https://github.com/dukefirehawk/angel/tree/angel3/packages/client)
provides a facility for this, which works perfectly with the default callback provided in this package.
```dart ```dart
configureServer(Angel app) async { configureServer(Angel app) async {
@ -77,8 +75,7 @@ configureServer(Angel app) async {
} }
``` ```
This renders a simple HTML page that fires the user's JWT as a `token` event in `window.opener`. This renders a simple HTML page that fires the user's JWT as a `token` event in `window.opener`. `angel3_client` [exposes this as a Stream](https://github.com/dukefirehawk/angel/tree/angel3/packages/client#authentication):
`angel3_client` [exposes this as a Stream](https://github.com/dukefirehawk/angel/tree/angel3/packages/client#authentication):
```dart ```dart
app.authenticateViaPopup('/auth/google').listen((jwt) { app.authenticateViaPopup('/auth/google').listen((jwt) {

View file

@ -352,9 +352,12 @@ class AngelAuth<User> {
/// or a `401 Not Authenticated` is thrown, if it is the last one. /// or a `401 Not Authenticated` is thrown, if it is the last one.
/// ///
/// Any other result is considered an authenticated user, and terminates the loop. /// Any other result is considered an authenticated user, and terminates the loop.
RequestHandler authenticate(type, [AngelAuthOptions<User>? options]) { RequestHandler authenticate(type, [AngelAuthOptions<User>? opt]) {
return (RequestContext req, ResponseContext res) async { return (RequestContext req, ResponseContext res) async {
var authOption = opt ?? AngelAuthOptions<User>();
var names = <String>[]; var names = <String>[];
var arr = type is Iterable var arr = type is Iterable
? type.map((x) => x.toString()).toList() ? type.map((x) => x.toString()).toList()
: [type.toString()]; : [type.toString()];
@ -386,11 +389,12 @@ class AngelAuth<User> {
var hasExisting = reqContainer?.has<User>() ?? false; var hasExisting = reqContainer?.has<User>() ?? false;
var result = hasExisting var result = hasExisting
? reqContainer?.make<User>() ? reqContainer?.make<User>()
: await strategy.authenticate(req, res, options); : await strategy.authenticate(req, res, authOption);
if (result != null && result == true) { if (result == true) {
return result; return result;
} else if (result != false && result != null) { } else if (result != null && result != false) {
//} else if (result != null && result is Map && result.isNotEmpty) {
var userId = await serializer(result); var userId = await serializer(result);
// Create JWT // Create JWT
@ -398,13 +402,13 @@ class AngelAuth<User> {
userId: userId, lifeSpan: _jwtLifeSpan, ipAddress: req.ip); userId: userId, lifeSpan: _jwtLifeSpan, ipAddress: req.ip);
var jwt = token.serialize(_hs256); var jwt = token.serialize(_hs256);
if (options != null && options.tokenCallback != null) { if (authOption.tokenCallback != null) {
var hasUser = reqContainer?.has<User>() ?? false; var hasUser = reqContainer?.has<User>() ?? false;
if (!hasUser) { if (!hasUser) {
reqContainer?.registerSingleton<User>(result); reqContainer?.registerSingleton<User>(result);
} }
var r = await options.tokenCallback!(req, res, token, result); var r = await authOption.tokenCallback!(req, res, token, result);
if (r != null) return r; if (r != null) return r;
jwt = token.serialize(_hs256); jwt = token.serialize(_hs256);
} }
@ -416,24 +420,15 @@ class AngelAuth<User> {
} }
// Options is not null // Options is not null
if (options != null) { if (authOption.callback != null) {
if (options.callback != null) { return await authOption.callback!(req, res, jwt);
return await options.callback!(req, res, jwt); }
}
if (options.successRedirect?.isNotEmpty == true) { if (authOption.successRedirect?.isNotEmpty == true) {
await res.redirect(options.successRedirect); await res.redirect(authOption.successRedirect);
return false; return false;
} else if (options.canRespondWithJson && } else if (authOption.canRespondWithJson &&
req.accepts('application/json')) { req.accepts('application/json')) {
var user = hasExisting
? result
: await deserializer((await serializer(result)) as Object);
_onLogin.add(user);
return {'data': user, 'token': jwt};
}
// Options is null
} else if (hasExisting && req.accepts('application/json')) {
var user = hasExisting var user = hasExisting
? result ? result
: await deserializer((await serializer(result)) as Object); : await deserializer((await serializer(result)) as Object);
@ -449,8 +444,8 @@ class AngelAuth<User> {
res.statusCode == 302 || res.statusCode == 302 ||
res.headers.containsKey('location')) { res.headers.containsKey('location')) {
return false; return false;
} else if (options != null && options.failureRedirect != null) { } else if (authOption.failureRedirect != null) {
await res.redirect(options.failureRedirect); await res.redirect(authOption.failureRedirect);
return false; return false;
} else { } else {
_log.warning('Not authenticated'); _log.warning('Not authenticated');

View file

@ -86,7 +86,8 @@ class LocalAuthStrategy<User> extends AuthStrategy<User> {
//} //}
} }
if (verificationResult == null) { if (verificationResult == null ||
(verificationResult is Map && verificationResult.isEmpty)) {
if (options.failureRedirect != null && if (options.failureRedirect != null &&
options.failureRedirect!.isNotEmpty) { options.failureRedirect!.isNotEmpty) {
await res.redirect(options.failureRedirect, code: 401); await res.redirect(options.failureRedirect, code: 401);
@ -99,7 +100,8 @@ class LocalAuthStrategy<User> extends AuthStrategy<User> {
} }
return null; return null;
} else if (verificationResult != false) { } else if (verificationResult != false ||
(verificationResult is Map && verificationResult.isNotEmpty)) {
return verificationResult; return verificationResult;
} else { } else {
_log.info('Not authenticated'); _log.info('Not authenticated');

View file

@ -1,6 +1,6 @@
name: angel3_auth name: angel3_auth
description: A complete authentication plugin for Angel. Includes support for stateless JWT tokens, Basic Auth, and more. description: A complete authentication plugin for Angel. Includes support for stateless JWT tokens, Basic Auth, and more.
version: 4.0.4 version: 4.0.5
homepage: https://angel3-framework.web.app/ homepage: https://angel3-framework.web.app/
repository: https://github.com/dukefirehawk/angel/tree/angel3/packages/auth repository: https://github.com/dukefirehawk/angel/tree/angel3/packages/auth
environment: environment:

View file

@ -12,14 +12,16 @@ final AngelAuth<Map<String, String>> auth = AngelAuth<Map<String, String>>(
var headers = <String, String>{'accept': 'application/json'}; var headers = <String, String>{'accept': 'application/json'};
var localOpts = AngelAuthOptions<Map<String, String>>( var localOpts = AngelAuthOptions<Map<String, String>>(
failureRedirect: '/failure', successRedirect: '/success'); failureRedirect: '/failure', successRedirect: '/success');
var localOpts2 =
AngelAuthOptions<Map<String, String>>(canRespondWithJson: false);
Map<String, String> sampleUser = {'hello': 'world'}; Map<String, String> sampleUser = {'hello': 'world'};
Future<Map<String, String>?> verifier( Future<Map<String, String>> verifier(String? username, String? password) async {
String? username, String? password) async {
if (username == 'username' && password == 'password') { if (username == 'username' && password == 'password') {
return sampleUser; return sampleUser;
} else { } else {
return null; return {};
} }
} }
@ -46,7 +48,7 @@ void main() async {
app.get('/hello', (req, res) { app.get('/hello', (req, res) {
// => 'Woo auth' // => 'Woo auth'
return 'Woo auth'; return 'Woo auth';
}, middleware: [auth.authenticate('local')]); }, middleware: [auth.authenticate('local', localOpts2)]);
app.post('/login', (req, res) => 'This should not be shown', app.post('/login', (req, res) => 'This should not be shown',
middleware: [auth.authenticate('local', localOpts)]); middleware: [auth.authenticate('local', localOpts)]);
app.get('/success', (req, res) => 'yep', middleware: [ app.get('/success', (req, res) => 'yep', middleware: [