Use async injection instead of decodeJwt

This commit is contained in:
Tobe O 2019-04-19 05:08:06 -04:00
parent b6acfb1573
commit 53b249da8b
8 changed files with 91 additions and 16 deletions

View file

@ -1,3 +1,6 @@
# 2.1.4
* Deprecate `decodeJwt`, in favor of asynchronous injections.
# 2.1.3
* Use `await` on redirects, etc.

View file

@ -17,13 +17,19 @@ Ensure you have read the [wiki](https://github.com/angel-dart/auth/wiki).
```dart
configureServer(Angel app) async {
var auth = AngelAuth();
var auth = AngelAuth<User>();
auth.serializer = ...;
auth.deserializer = ...;
auth.strategies['local'] = LocalAuthStrategy(...);
// POST route to handle username+password
app.post('/local', auth.authenticate('local'));
// Using Angel's asynchronous injections, we can parse the JWT
// on demand. It won't be parsed until we check.
app.get('/profile', ioc((User user) {
print(user.description);
}));
// Use a comma to try multiple strategies!!!
//
@ -37,11 +43,8 @@ configureServer(Angel app) async {
authOptions
);
// Apply angel_auth-specific configuration
// Apply angel_auth-specific configuration.
await app.configure(auth.configureServer);
// Middleware to decode JWT's...
app.use(auth.decodeJwt);
}
```

View file

@ -12,7 +12,7 @@ main() async {
auth.deserializer = (id) => fetchAUserByIdSomehow(id);
// Middleware to decode JWT's and inject a user object...
app.fallback(auth.decodeJwt);
await app.configure(auth.configureServer);
auth.strategies['local'] = LocalAuthStrategy((username, password) {
// Retrieve a user somehow...

View file

@ -1,3 +1,4 @@
import 'dart:async';
import 'package:angel_framework/angel_framework.dart';
/// Forces Basic authentication over the requested resource, with the given [realm] name, if no JWT is present.
@ -5,7 +6,13 @@ import 'package:angel_framework/angel_framework.dart';
/// [realm] defaults to `'angel_auth'`.
RequestHandler forceBasicAuth<User>({String realm}) {
return (RequestContext req, ResponseContext res) async {
if (req.container.has<User>()) return true;
if (req.container.has<User>())
return true;
else if (req.container.has<Future<User>>()) {
await req.container.makeAsync<User>();
return true;
}
res.headers['www-authenticate'] = 'Basic realm="${realm ?? 'angel_auth'}"';
throw AngelHttpException.notAuthenticated();
};
@ -25,7 +32,10 @@ RequestHandler requireAuthentication<User>() {
if (req.container.has<User>() || req.method == 'OPTIONS')
return true;
else
else if (req.container.has<Future<User>>()) {
await req.container.makeAsync<User>();
return true;
} else
return _reject(res);
};
}

View file

@ -89,7 +89,9 @@ class AngelAuth<User> {
_jwtLifeSpan = jwtLifeSpan?.toInt() ?? -1;
}
Future configureServer(Angel app) async {
/// Configures an Angel server to decode and validate JSON Web tokens on demand,
/// whenever an instance of [User] is injected.
Future<void> configureServer(Angel app) async {
if (serializer == null)
throw StateError(
'An `AngelAuth` plug-in was called without its `serializer` being set. All authentication will fail.');
@ -101,6 +103,30 @@ class AngelAuth<User> {
if (runtimeType != AngelAuth)
app.container.registerSingleton(this, as: AngelAuth);
if (!app.container.has<_AuthResult<User>>()) {
app.container
.registerLazySingleton<Future<_AuthResult<User>>>((container) async {
var req = container.make<RequestContext>();
var res = container.make<ResponseContext>();
var result = await _decodeJwt(req, res);
if (result != null) {
return result;
} else {
throw AngelHttpException.forbidden();
}
});
app.container.registerLazySingleton<Future<User>>((container) async {
var result = await container.makeAsync<_AuthResult<User>>();
return result.user;
});
app.container.registerLazySingleton<Future<AuthToken>>((container) async {
var result = await container.makeAsync<_AuthResult<User>>();
return result.token;
});
}
if (reviveTokenEndpoint != null) {
app.post(reviveTokenEndpoint, reviveJwt);
}
@ -112,7 +138,7 @@ class AngelAuth<User> {
void _apply(
RequestContext req, ResponseContext res, AuthToken token, User user) {
if (!req.container.has<User>()) {
if (!req.container.has<User>() && !req.container.has<Future<User>>()) {
req.container
..registerSingleton<AuthToken>(token)
..registerSingleton<User>(user);
@ -123,12 +149,39 @@ class AngelAuth<User> {
}
}
/// A middleware that decodes a JWT from a request, and injects a corresponding user.
/// DEPRECATED: A middleware that decodes a JWT from a request, and injects a corresponding user.
///
/// Now that `package:angel_framework` supports asynchronous injections, this middleware
/// is no longer directly necessary. Instead, call [configureServer]. You can then use
/// `makeAsync<User>`, or Angel's injections directly:
///
/// ```dart
/// var auth = AngelAuth<User>(...);
/// await app.configure(auth.configureServer);
///
/// app.get('/hmm', (User user) async {
/// // `package:angel_auth` decodes the JWT on demand.
/// print(user.name);
/// });
///
/// @Expose('/my')
/// class MyController extends Controller {
/// @Expose('/hmm')
/// String getUsername(User user) => user.name
/// }
/// ```
@deprecated
Future decodeJwt(RequestContext req, ResponseContext res) async {
if (req.method == "POST" && req.path == reviveTokenEndpoint) {
return await reviveJwt(req, res);
} else {
await _decodeJwt(req, res);
return true;
}
}
Future<_AuthResult<User>> _decodeJwt(
RequestContext req, ResponseContext res) async {
String jwt = getJwt(req);
if (jwt != null) {
@ -148,11 +201,12 @@ class AngelAuth<User> {
throw AngelHttpException.forbidden(message: "Expired JWT.");
}
final user = await deserializer(token.userId);
var user = await deserializer(token.userId);
_apply(req, res, token, user);
return _AuthResult(user, token);
}
return true;
return null;
}
/// Retrieves a JWT from a request, if any was sent at all.
@ -384,3 +438,10 @@ class AngelAuth<User> {
};
}
}
class _AuthResult<User> {
final User user;
final AuthToken token;
_AuthResult(this.user, this.token);
}

View file

@ -1,6 +1,6 @@
name: angel_auth
description: A complete authentication plugin for Angel. Includes support for stateless JWT tokens, Basic Auth, and more.
version: 2.1.3
version: 2.1.4
author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/angel_auth
environment:

View file

@ -75,7 +75,6 @@ main() {
(id) async => await app.findService('users').read(id) as User;
await app.configure(auth.configureServer);
app.fallback(auth.decodeJwt);
auth.strategies['local'] = LocalAuthStrategy((username, password) async {
var users = await app

View file

@ -27,7 +27,6 @@ Future wireAuth(Angel app) async {
auth.strategies['local'] = LocalAuthStrategy(verifier);
await app.configure(auth.configureServer);
app.fallback(auth.decodeJwt);
}
main() async {