diff --git a/.idea/angel_auth.iml b/.idea/angel_auth.iml index a928d34a..3889dae0 100644 --- a/.idea/angel_auth.iml +++ b/.idea/angel_auth.iml @@ -12,7 +12,7 @@ - + \ No newline at end of file diff --git a/README.md b/README.md index c80af146..cfd6077b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # angel_auth -[![version 1.0.2](https://img.shields.io/badge/version-1.0.2-brightgreen.svg)](https://pub.dartlang.org/packages/angel_auth) +[![version 1.0.3](https://img.shields.io/badge/version-1.0.3-brightgreen.svg)](https://pub.dartlang.org/packages/angel_auth) ![build status](https://travis-ci.org/angel-dart/auth.svg?branch=master) A complete authentication plugin for Angel. Inspired by Passport. diff --git a/lib/src/middleware/require_auth.dart b/lib/src/middleware/require_auth.dart index da8343a5..77da3ca1 100644 --- a/lib/src/middleware/require_auth.dart +++ b/lib/src/middleware/require_auth.dart @@ -2,8 +2,29 @@ import 'dart:async'; import 'dart:io'; import 'package:angel_framework/angel_framework.dart'; +/// Restricts access to a resource via authentication. Constant instance. +const RequestMiddleware requireAuth = const RequireAuthorizationMiddleware(); + +/// Forces Basic authentication over the requested resource, with the given [realm] name, if no JWT is present. +/// +/// [realm] defaults to `'angel_auth'`. +RequestHandler forceBasicAuth({String realm}) { + return (RequestContext req, ResponseContext res) async { + if (req.properties.containsKey('user')) return true; + + res + ..statusCode = HttpStatus.UNAUTHORIZED + ..headers[HttpHeaders.WWW_AUTHENTICATE] = + 'Basic realm="${realm ?? 'angel_auth'}"' + ..end(); + return false; + }; +} + /// Restricts access to a resource via authentication. -class RequireAuthorizationMiddleware extends AngelMiddleware { +class RequireAuthorizationMiddleware implements AngelMiddleware { + const RequireAuthorizationMiddleware(); + @override Future call(RequestContext req, ResponseContext res, {bool throwError: true}) async { diff --git a/lib/src/plugin.dart b/lib/src/plugin.dart index 16313362..6c6bc1a4 100644 --- a/lib/src/plugin.dart +++ b/lib/src/plugin.dart @@ -14,8 +14,6 @@ class AngelAuth extends AngelPlugin { num _jwtLifeSpan; Math.Random _random = new Math.Random.secure(); final RegExp _rgxBearer = new RegExp(r"^Bearer"); - RequireAuthorizationMiddleware _requireAuth = - new RequireAuthorizationMiddleware(); final bool allowCookie; final bool allowTokenInQuery; String middlewareName; @@ -59,13 +57,19 @@ class AngelAuth extends AngelPlugin { if (runtimeType != AngelAuth) app.container.singleton(this, as: AngelAuth); app.before.add(decodeJwt); - app.registerMiddleware(middlewareName, _requireAuth); + app.registerMiddleware(middlewareName, requireAuth); if (reviveTokenEndpoint != null) { app.post(reviveTokenEndpoint, reviveJwt); } } + void _apply(RequestContext req, AuthToken token, user) { + req + ..inject(AuthToken, req.properties['token'] = token) + ..inject(user.runtimeType, req.properties["user"] = user); + } + decodeJwt(RequestContext req, ResponseContext res) async { if (req.method == "POST" && req.path == reviveTokenEndpoint) { // Shouldn't block invalid JWT if we are reviving it @@ -119,10 +123,7 @@ class AngelAuth extends AngelPlugin { } final user = await deserializer(token.userId); - - req - ..inject(AuthToken, req.properties['token'] = token) - ..inject(user.runtimeType, req.properties["user"] = user); + _apply(req, token, user); } return true; @@ -243,9 +244,7 @@ class AngelAuth extends AngelPlugin { if (r != null) return r; } - req - ..inject(AuthToken, req.properties['token'] = token) - ..inject(result.runtimeType, req.properties["user"] = result); + _apply(req, token, result); if (allowCookie) res.cookies.add(new Cookie("token", jwt)); @@ -254,13 +253,15 @@ class AngelAuth extends AngelPlugin { } if (options?.successRedirect?.isNotEmpty == true) { - return res.redirect(options.successRedirect, code: HttpStatus.OK); + res.redirect(options.successRedirect, code: HttpStatus.OK); + return false; } else if (options?.canRespondWithJson != false && req.headers.value("accept") != null && (req.headers.value("accept").contains("application/json") || req.headers.value("accept").contains("*/*") || req.headers.value("accept").contains("application/*"))) { - return {"data": result, "token": jwt}; + var user = await deserializer(await serializer(result)); + return {"data": user, "token": jwt}; } return true; @@ -277,10 +278,7 @@ class AngelAuth extends AngelPlugin { /// Log a user in on-demand. Future login(AuthToken token, RequestContext req, ResponseContext res) async { var user = await deserializer(token.userId); - - req - ..inject(AuthToken, req.properties['token'] = token) - ..inject(user.runtimeType, req.properties["user"] = user); + _apply(req, token, user); if (allowCookie) res.cookies.add(new Cookie('token', token.serialize(_hs256))); @@ -291,10 +289,7 @@ class AngelAuth extends AngelPlugin { var user = await deserializer(userId); var token = new AuthToken( userId: userId, lifeSpan: _jwtLifeSpan, ipAddress: req.ip); - - req - ..inject(AuthToken, req.properties['token'] = token) - ..inject(user.runtimeType, req.properties["user"] = user); + _apply(req, token, user); if (allowCookie) res.cookies.add(new Cookie('token', token.serialize(_hs256))); diff --git a/pubspec.yaml b/pubspec.yaml index 44a04166..15e95380 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: angel_auth description: A complete authentication plugin for Angel. -version: 1.0.2 +version: 1.0.3 author: Tobe O homepage: https://github.com/angel-dart/angel_auth environment: