Hooks
This commit is contained in:
parent
84bcb05fdd
commit
cbddcc72a4
3 changed files with 28 additions and 42 deletions
|
@ -4,7 +4,7 @@ import 'package:angel_framework/common.dart';
|
|||
|
||||
class User extends Model {
|
||||
String email, username, password, salt;
|
||||
final List<String> roles = [];
|
||||
List<String> roles;
|
||||
|
||||
User(
|
||||
{String id,
|
||||
|
@ -12,8 +12,7 @@ class User extends Model {
|
|||
this.username,
|
||||
this.password,
|
||||
this.salt,
|
||||
Iterable<String> roles: const []}) {
|
||||
this.roles: const []}) {
|
||||
this.id = id;
|
||||
this.roles.addAll(roles ?? []);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,11 +7,16 @@ import '../../services/user.dart';
|
|||
class AuthController extends Controller {
|
||||
AngelAuth auth;
|
||||
|
||||
deserializer(String id) async => app.service('api/users').read(id);
|
||||
/// Clients will see the result of `deserializer`, so let's pretend to be a client.
|
||||
///
|
||||
/// Our User service is already wired to remove sensitive data from serialized JSON.
|
||||
deserializer(String id) async =>
|
||||
app.service('api/users').read(id, {'provider': Providers.VIA_REST});
|
||||
|
||||
serializer(User user) async => user.id;
|
||||
|
||||
/// Attempt to log a user in
|
||||
LocalAuthVerifier localVerifier(UserService userService) {
|
||||
LocalAuthVerifier localVerifier(Service userService) {
|
||||
return (String username, String password) async {
|
||||
List<User> users = await userService.index({
|
||||
'query': {'username': username}
|
||||
|
@ -32,8 +37,8 @@ class AuthController extends Controller {
|
|||
auth = new AngelAuth(jwtKey: app.jwt_secret)
|
||||
..serializer = serializer
|
||||
..deserializer = deserializer
|
||||
..strategies.add(new LocalAuthStrategy(
|
||||
localVerifier(app.container.make(UserService))));
|
||||
..strategies
|
||||
.add(new LocalAuthStrategy(localVerifier(app.service('api/users'))));
|
||||
|
||||
await super.call(app);
|
||||
await app.configure(auth);
|
||||
|
@ -41,9 +46,4 @@ class AuthController extends Controller {
|
|||
|
||||
@Expose('/local', method: 'POST')
|
||||
login() => auth.authenticate('local');
|
||||
|
||||
@Expose('/register', method: 'POST')
|
||||
register(RequestContext req, UserService userService) async {
|
||||
// And your registration logic...
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:angel_common/angel_common.dart';
|
||||
import 'package:angel_framework/hooks.dart' as hooks;
|
||||
import 'package:crypto/crypto.dart' show sha256;
|
||||
import 'package:mongo_dart/mongo_dart.dart';
|
||||
import 'package:random_string/random_string.dart' as rs;
|
||||
|
@ -8,11 +9,22 @@ export '../models/user.dart';
|
|||
|
||||
configureServer(Db db) {
|
||||
return (Angel app) async {
|
||||
app.use('/api/users', new UserService(db.collection('users')));
|
||||
app.use('/api/users',
|
||||
new TypedService<User>(new MongoService(db.collection('users'))));
|
||||
|
||||
HookedService service = app.service('api/users');
|
||||
app.container.singleton(service.inner);
|
||||
|
||||
// Prevent clients from doing anything to the `users` service,
|
||||
// apart from reading a single user's data.
|
||||
service.before([
|
||||
HookedServiceEvent.INDEXED,
|
||||
HookedServiceEvent.CREATED,
|
||||
HookedServiceEvent.MODIFIED,
|
||||
HookedServiceEvent.UPDATED,
|
||||
HookedServiceEvent.REMOVED
|
||||
], hooks.disable());
|
||||
|
||||
// Validate new users, and also hash their passwords.
|
||||
service.beforeCreated
|
||||
..listen(validateEvent(CREATE_USER))
|
||||
..listen((e) {
|
||||
|
@ -22,37 +34,12 @@ configureServer(Db db) {
|
|||
hashPassword(e.data['password'], salt, app.jwt_secret)
|
||||
..['salt'] = salt;
|
||||
});
|
||||
|
||||
// Remove sensitive data from serialized JSON.
|
||||
service.afterAll(hooks.remove(['password', 'salt']));
|
||||
};
|
||||
}
|
||||
|
||||
/// SHA-256 hash any string, particularly a password.
|
||||
String hashPassword(String password, String salt, String pepper) =>
|
||||
sha256.convert(('$salt:$password:$pepper').codeUnits).toString();
|
||||
|
||||
/// Manages users.
|
||||
///
|
||||
/// Here, we extended the base service class. This allows to only expose
|
||||
/// specific methods, and also allows more freedom over things such as validation.
|
||||
class UserService extends TypedService<User> {
|
||||
UserService(DbCollection collection) : super(new MongoService(collection));
|
||||
|
||||
@override
|
||||
index([Map params]) {
|
||||
if (params != null && params.containsKey('provider')) {
|
||||
// Nobody needs to see the entire user list except for the server.
|
||||
throw new AngelHttpException.forbidden();
|
||||
}
|
||||
|
||||
return super.index(params);
|
||||
}
|
||||
|
||||
@override
|
||||
create(data, [Map params]) {
|
||||
if (params != null && params.containsKey('provider')) {
|
||||
// Deny creating users to the public - this should be done by the server only.
|
||||
throw new AngelHttpException.forbidden();
|
||||
}
|
||||
|
||||
return super.create(data, params);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue