mirror of
https://github.com/jonasroussel/dart_jsonwebtoken.git
synced 2025-07-30 15:34:08 +08:00
v0.1.0
This commit is contained in:
@ -1,3 +1,3 @@
|
||||
## 1.0.0
|
||||
## 0.1.0
|
||||
|
||||
- Initial version, created by Stagehand
|
||||
- First version with every based features
|
||||
|
24
README.md
24
README.md
@ -1,22 +1,2 @@
|
||||
A library for Dart developers.
|
||||
|
||||
Created from templates made available by Stagehand under a BSD-style
|
||||
[license](https://github.com/dart-lang/stagehand/blob/master/LICENSE).
|
||||
|
||||
## Usage
|
||||
|
||||
A simple usage example:
|
||||
|
||||
```dart
|
||||
import 'package:jsonwebtoken/jsonwebtoken.dart';
|
||||
|
||||
main() {
|
||||
var awesome = new Awesome();
|
||||
}
|
||||
```
|
||||
|
||||
## Features and bugs
|
||||
|
||||
Please file feature requests and bugs at the [issue tracker][tracker].
|
||||
|
||||
[tracker]: http://example.com/issues/replaceme
|
||||
# JsonWebToken
|
||||
[](https://pub.dev/packages/jsonwebtoken)
|
||||
|
@ -1,11 +1,37 @@
|
||||
import 'package:jsonwebtoken/jsonwebtoken.dart';
|
||||
|
||||
main() {
|
||||
final token = JWT(
|
||||
payload: {
|
||||
'hello': 'world',
|
||||
},
|
||||
).sign(key: 'test');
|
||||
String token;
|
||||
|
||||
print(token);
|
||||
/* Sign */ {
|
||||
// Create a json web token
|
||||
final jwt = JWT(
|
||||
payload: {
|
||||
'id': 123,
|
||||
'server': {
|
||||
'id': '3e4fc296',
|
||||
'loc': 'euw-2',
|
||||
}
|
||||
},
|
||||
issuer: 'https://github.com/jonasroussel/jsonwebtoken',
|
||||
);
|
||||
|
||||
// Sign it
|
||||
token = jwt.sign('secret-key');
|
||||
|
||||
print('Signed token: $token\n');
|
||||
}
|
||||
|
||||
/* Verify */ {
|
||||
try {
|
||||
// Verify a token
|
||||
final jwt = JWT.verify(token, 'secret-key');
|
||||
|
||||
print('Payload: ${jwt.payload}');
|
||||
} on JWTExpiredError {
|
||||
print('jwt expired');
|
||||
} on JWTError catch (ex) {
|
||||
print(ex.message); // ex: invalid signature
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
library jsonwebtoken;
|
||||
|
||||
export 'src/jsonwebtoken.dart';
|
||||
export 'src/jwt.dart';
|
||||
export 'src/errors.dart';
|
||||
export 'src/algorithms.dart';
|
||||
|
49
lib/src/algorithms.dart
Normal file
49
lib/src/algorithms.dart
Normal file
@ -0,0 +1,49 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'package:jsonwebtoken/jsonwebtoken.dart';
|
||||
|
||||
abstract class JWTAlgorithm {
|
||||
static const HS256 = HS256Algorithm();
|
||||
|
||||
static JWTAlgorithm fromName(String name) {
|
||||
switch (name) {
|
||||
case 'HS256':
|
||||
return JWTAlgorithm.HS256;
|
||||
default:
|
||||
throw JWTInvalidError('unknown algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
const JWTAlgorithm();
|
||||
|
||||
String get name;
|
||||
List<int> sign(String key, List<int> body);
|
||||
bool verify(String key, List<int> body, List<int> signature);
|
||||
}
|
||||
|
||||
class HS256Algorithm extends JWTAlgorithm {
|
||||
const HS256Algorithm();
|
||||
|
||||
@override
|
||||
String get name => 'HS256';
|
||||
|
||||
@override
|
||||
List<int> sign(String key, List<int> body) {
|
||||
final hmac = Hmac(sha256, utf8.encode(key));
|
||||
return hmac.convert(body).bytes;
|
||||
}
|
||||
|
||||
@override
|
||||
bool verify(String key, List<int> body, List<int> signature) {
|
||||
final actual = sign(key, body);
|
||||
|
||||
if (actual.length != signature.length) return false;
|
||||
|
||||
for (var i = 0; i < actual.length; i++) {
|
||||
if (actual[i] != signature[i]) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
13
lib/src/errors.dart
Normal file
13
lib/src/errors.dart
Normal file
@ -0,0 +1,13 @@
|
||||
class JWTError extends Error {
|
||||
JWTError(this.message);
|
||||
|
||||
final String message;
|
||||
}
|
||||
|
||||
class JWTInvalidError extends JWTError {
|
||||
JWTInvalidError(String message) : super(message);
|
||||
}
|
||||
|
||||
class JWTExpiredError extends JWTError {
|
||||
JWTExpiredError() : super('jwt expired');
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:crypto/crypto.dart';
|
||||
|
||||
class JWT {
|
||||
JWT({
|
||||
this.payload = const {},
|
||||
this.audience,
|
||||
this.subject,
|
||||
this.issuer,
|
||||
});
|
||||
|
||||
static String secretKey = null;
|
||||
|
||||
final _jsonToBase64Url = json.fuse(utf8.fuse(base64Url));
|
||||
|
||||
final Map<String, dynamic> payload;
|
||||
final String audience;
|
||||
final String subject;
|
||||
final String issuer;
|
||||
|
||||
String signedToken;
|
||||
|
||||
String sign({
|
||||
String key,
|
||||
Duration expiresIn = null,
|
||||
bool noTimestamp = false,
|
||||
}) {
|
||||
if (key == null && JWT.secretKey != null) key = JWT.secretKey;
|
||||
assert(key != null);
|
||||
|
||||
final header = {'alg': 'HS256', 'typ': 'JWT'};
|
||||
final algorithm = HS256Algorithm(key);
|
||||
|
||||
// Creation timestamp
|
||||
if (!noTimestamp)
|
||||
payload['iat'] = DateTime.now();
|
||||
else
|
||||
payload.remove('iat');
|
||||
|
||||
// Expiration timestamp
|
||||
if (expiresIn != null)
|
||||
payload['exp'] = DateTime.now().add(expiresIn);
|
||||
else
|
||||
payload.remove('exp');
|
||||
|
||||
final body = _jsonToBase64Url.encode(header) + '.' + _jsonToBase64Url.encode(payload);
|
||||
final signature = base64Url.encode(algorithm.sign(utf8.encode(body)));
|
||||
|
||||
return (signedToken = (body + '.' + signature));
|
||||
}
|
||||
|
||||
static JWT verify(String token) {}
|
||||
}
|
||||
|
||||
abstract class JWTAlgorithm {
|
||||
const JWTAlgorithm();
|
||||
|
||||
String get name;
|
||||
List<int> sign(List<int> body);
|
||||
bool verify(List<int> body, List<int> signature);
|
||||
}
|
||||
|
||||
class HS256Algorithm extends JWTAlgorithm {
|
||||
const HS256Algorithm(this.secretKey);
|
||||
|
||||
final String secretKey;
|
||||
|
||||
@override
|
||||
String get name => 'HS256';
|
||||
|
||||
@override
|
||||
List<int> sign(List<int> body) {
|
||||
final hmac = Hmac(sha256, utf8.encode(secretKey));
|
||||
return hmac.convert(body).bytes;
|
||||
}
|
||||
|
||||
@override
|
||||
bool verify(List<int> body, List<int> signature) {
|
||||
final actual = sign(body);
|
||||
|
||||
if (actual.length != signature.length) return false;
|
||||
|
||||
for (var i = 0; i < actual.length; i++) {
|
||||
if (actual[i] != signature[i]) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
80
lib/src/jwt.dart
Normal file
80
lib/src/jwt.dart
Normal file
@ -0,0 +1,80 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:jsonwebtoken/jsonwebtoken.dart';
|
||||
|
||||
import './utils.dart';
|
||||
|
||||
class JWT {
|
||||
static JWT verify(String token, String key) {
|
||||
try {
|
||||
final parts = token.split('.');
|
||||
|
||||
final header = Map<String, dynamic>.from(jsonBase64.decode(base64Padded(parts[0])));
|
||||
|
||||
if (header['typ'] != 'JWT') throw JWTInvalidError('not a jwt');
|
||||
|
||||
final algorithm = JWTAlgorithm.fromName(header['alg']);
|
||||
|
||||
if (parts.length < 3) throw JWTInvalidError('jwt malformated');
|
||||
|
||||
final body = utf8.encode(parts[0] + '.' + parts[1]);
|
||||
final signature = base64Url.decode(base64Padded(parts[2]));
|
||||
|
||||
if (!algorithm.verify(key, body, signature)) {
|
||||
throw JWTInvalidError('invalid signature');
|
||||
}
|
||||
|
||||
final payload = Map<String, dynamic>.from(jsonBase64.decode(base64Padded(parts[1])));
|
||||
|
||||
if (payload.containsKey('exp')) {
|
||||
final exp = DateTime.fromMillisecondsSinceEpoch(payload['exp'] * 1000);
|
||||
if (exp.isBefore(DateTime.now())) {
|
||||
throw JWTExpiredError();
|
||||
}
|
||||
}
|
||||
|
||||
return JWT(
|
||||
payload: payload,
|
||||
audience: payload.remove('aud'),
|
||||
issuer: payload.remove('iss'),
|
||||
subject: payload.remove('sub'),
|
||||
);
|
||||
} on JWTError catch (ex) {
|
||||
throw ex;
|
||||
} catch (ex) {
|
||||
throw JWTInvalidError('jwt invalid');
|
||||
}
|
||||
}
|
||||
|
||||
JWT({
|
||||
this.payload = const {},
|
||||
this.audience,
|
||||
this.subject,
|
||||
this.issuer,
|
||||
});
|
||||
|
||||
final Map<String, dynamic> payload;
|
||||
final String audience;
|
||||
final String subject;
|
||||
final String issuer;
|
||||
|
||||
String sign(
|
||||
String key, {
|
||||
JWTAlgorithm algorithm = JWTAlgorithm.HS256,
|
||||
Duration expiresIn = null,
|
||||
bool noTimestamp = false,
|
||||
}) {
|
||||
final header = {'alg': algorithm.name, 'typ': 'JWT'};
|
||||
|
||||
if (!noTimestamp) payload['iat'] = secondsSinceEpoch(DateTime.now());
|
||||
if (expiresIn != null) payload['exp'] = secondsSinceEpoch(DateTime.now().add(expiresIn));
|
||||
if (audience != null) payload['aud'] = audience;
|
||||
if (subject != null) payload['sub'] = subject;
|
||||
if (issuer != null) payload['iss'] = issuer;
|
||||
|
||||
final body = base64Unpadded(jsonBase64.encode(header)) + '.' + base64Unpadded(jsonBase64.encode(payload));
|
||||
final signature = base64Unpadded(base64Url.encode(algorithm.sign(key, utf8.encode(body))));
|
||||
|
||||
return body + '.' + signature;
|
||||
}
|
||||
}
|
26
lib/src/utils.dart
Normal file
26
lib/src/utils.dart
Normal file
@ -0,0 +1,26 @@
|
||||
import 'dart:convert';
|
||||
|
||||
final jsonBase64 = json.fuse(utf8.fuse(base64Url));
|
||||
|
||||
String base64Unpadded(String value) {
|
||||
if (value.endsWith('==')) return value.substring(0, value.length - 2);
|
||||
if (value.endsWith('=')) return value.substring(0, value.length - 1);
|
||||
return value;
|
||||
}
|
||||
|
||||
String base64Padded(String value) {
|
||||
final lenght = value.length;
|
||||
|
||||
switch (lenght % 4) {
|
||||
case 2:
|
||||
return value.padRight(lenght + 2, '=');
|
||||
case 3:
|
||||
return value.padRight(lenght + 1, '=');
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
int secondsSinceEpoch(DateTime time) {
|
||||
return time.millisecondsSinceEpoch ~/ 1000;
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
name: jsonwebtoken
|
||||
description: A starting point for Dart libraries or applications.
|
||||
version: 1.0.0
|
||||
homepage: https://www.example.com
|
||||
description: A dart implementation of JSON Web Tokens.
|
||||
version: 0.1.0
|
||||
repository: https://github.com/jonasroussel/jsonwebtoken
|
||||
homepage: https://github.com/jonasroussel/jsonwebtoken#readme
|
||||
|
||||
environment:
|
||||
sdk: '>=2.7.0 <3.0.0'
|
||||
|
Reference in New Issue
Block a user