Use async injection instead of decodeJwt
This commit is contained in:
parent
b6acfb1573
commit
53b249da8b
8 changed files with 91 additions and 16 deletions
|
@ -1,3 +1,6 @@
|
|||
# 2.1.4
|
||||
* Deprecate `decodeJwt`, in favor of asynchronous injections.
|
||||
|
||||
# 2.1.3
|
||||
* Use `await` on redirects, etc.
|
||||
|
||||
|
|
13
README.md
13
README.md
|
@ -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);
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -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...
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue