This commit is contained in:
thosakwe 2017-01-20 18:15:21 -05:00
parent 771a4e8a5c
commit e163c1b9e9
6 changed files with 80 additions and 4 deletions

View file

@ -1,6 +1,6 @@
# angel_auth # angel_auth
[![version 1.1.0-dev+17](https://img.shields.io/badge/version-1.1.0--dev+17-red.svg)](https://pub.dartlang.org/packages/angel_auth) [![version 1.1.0-dev+18](https://img.shields.io/badge/version-1.1.0--dev+18-red.svg)](https://pub.dartlang.org/packages/angel_auth)
![build status](https://travis-ci.org/angel-dart/auth.svg?branch=master) ![build status](https://travis-ci.org/angel-dart/auth.svg?branch=master)
A complete authentication plugin for Angel. Inspired by Passport. A complete authentication plugin for Angel. Inspired by Passport.

4
lib/auth_token.dart Normal file
View file

@ -0,0 +1,4 @@
/// Stand-alone JWT library.
library angel_auth.auth_token;
export 'src/auth_token.dart';

View file

@ -3,6 +3,27 @@ import 'dart:convert';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel_framework/angel_framework.dart';
import 'package:crypto/crypto.dart'; import 'package:crypto/crypto.dart';
/// Calls [BASE64URL], but also works for strings with lengths
/// that are *not* multiples of 4.
String decodeBase64(String str) {
var output = str.replaceAll('-', '+').replaceAll('_', '/');
switch (output.length % 4) {
case 0:
break;
case 2:
output += '==';
break;
case 3:
output += '=';
break;
default:
throw 'Illegal base64url string!"';
}
return UTF8.decode(BASE64URL.decode(output));
}
class AuthToken { class AuthToken {
final SplayTreeMap<String, String> _header = final SplayTreeMap<String, String> _header =
new SplayTreeMap.from({"alg": "HS256", "typ": "JWT"}); new SplayTreeMap.from({"alg": "HS256", "typ": "JWT"});
@ -35,14 +56,24 @@ class AuthToken {
payload: data["pld"] ?? {}); payload: data["pld"] ?? {});
} }
factory AuthToken.parse(String jwt) {
var split = jwt.split(".");
if (split.length != 3)
throw new AngelHttpException.notAuthenticated(message: "Invalid JWT.");
var payloadString = decodeBase64(split[1]);
return new AuthToken.fromMap(JSON.decode(payloadString));
}
factory AuthToken.validate(String jwt, Hmac hmac) { factory AuthToken.validate(String jwt, Hmac hmac) {
var split = jwt.split("."); var split = jwt.split(".");
if (split.length != 3) if (split.length != 3)
throw new AngelHttpException.notAuthenticated(message: "Invalid JWT."); throw new AngelHttpException.notAuthenticated(message: "Invalid JWT.");
// var headerString = new String.fromCharCodes(BASE64URL.decode(split[0])); // var headerString = decodeBase64(split[0]);
var payloadString = new String.fromCharCodes(BASE64URL.decode(split[1])); var payloadString = decodeBase64(split[1]);
var data = split[0] + "." + split[1]; var data = split[0] + "." + split[1];
var signature = BASE64URL.encode(hmac.convert(data.codeUnits).bytes); var signature = BASE64URL.encode(hmac.convert(data.codeUnits).bytes);

View file

@ -1,16 +1,22 @@
import 'package:angel_framework/angel_framework.dart'; import 'package:angel_framework/angel_framework.dart';
import 'auth_token.dart';
typedef AngelAuthCallback( typedef AngelAuthCallback(
RequestContext req, ResponseContext res, String token); RequestContext req, ResponseContext res, String token);
typedef AngelAuthTokenCallback(
RequestContext req, ResponseContext res, AuthToken token, user);
class AngelAuthOptions { class AngelAuthOptions {
AngelAuthCallback callback; AngelAuthCallback callback;
AngelAuthTokenCallback tokenCallback;
bool canRespondWithJson; bool canRespondWithJson;
String successRedirect; String successRedirect;
String failureRedirect; String failureRedirect;
AngelAuthOptions( AngelAuthOptions(
{this.callback, {this.callback,
this.tokenCallback,
this.canRespondWithJson: true, this.canRespondWithJson: true,
this.successRedirect, this.successRedirect,
String this.failureRedirect}); String this.failureRedirect});

View file

@ -26,6 +26,8 @@ class AngelAuth extends AngelPlugin {
UserSerializer serializer; UserSerializer serializer;
UserDeserializer deserializer; UserDeserializer deserializer;
Hmac get hmac => _hs256;
String _randomString( String _randomString(
{int length: 32, {int length: 32,
String validChars: String validChars:
@ -234,6 +236,13 @@ class AngelAuth extends AngelPlugin {
var token = new AuthToken( var token = new AuthToken(
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?.tokenCallback != null) {
var r = await options.tokenCallback(
req, res, token, req.properties["user"] = result);
if (r != null) return r;
}
req req
..inject(AuthToken, req.properties['token'] = token) ..inject(AuthToken, req.properties['token'] = token)
..inject(result.runtimeType, req.properties["user"] = result); ..inject(result.runtimeType, req.properties["user"] = result);
@ -265,6 +274,32 @@ class AngelAuth extends AngelPlugin {
throw new AngelHttpException.notAuthenticated(); throw new AngelHttpException.notAuthenticated();
} }
/// 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);
if (allowCookie)
res.cookies.add(new Cookie('token', token.serialize(_hs256)));
}
/// Log a user in on-demand.
Future loginById(userId, RequestContext req, ResponseContext res) async {
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);
if (allowCookie)
res.cookies.add(new Cookie('token', token.serialize(_hs256)));
}
logout([AngelAuthOptions options]) { logout([AngelAuthOptions options]) {
return (RequestContext req, ResponseContext res) async { return (RequestContext req, ResponseContext res) async {
for (AuthStrategy strategy in strategies) { for (AuthStrategy strategy in strategies) {

View file

@ -1,6 +1,6 @@
name: angel_auth name: angel_auth
description: A complete authentication plugin for Angel. description: A complete authentication plugin for Angel.
version: 1.0.0-dev+17 version: 1.0.0-dev+18
author: Tobe O <thosakwe@gmail.com> author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/angel_auth homepage: https://github.com/angel-dart/angel_auth
environment: environment: