This commit is contained in:
thosakwe 2017-03-05 08:46:18 -05:00
parent 84bcb05fdd
commit cbddcc72a4
3 changed files with 28 additions and 42 deletions

View file

@ -4,7 +4,7 @@ import 'package:angel_framework/common.dart';
class User extends Model { class User extends Model {
String email, username, password, salt; String email, username, password, salt;
final List<String> roles = []; List<String> roles;
User( User(
{String id, {String id,
@ -12,8 +12,7 @@ class User extends Model {
this.username, this.username,
this.password, this.password,
this.salt, this.salt,
Iterable<String> roles: const []}) { this.roles: const []}) {
this.id = id; this.id = id;
this.roles.addAll(roles ?? []);
} }
} }

View file

@ -7,11 +7,16 @@ import '../../services/user.dart';
class AuthController extends Controller { class AuthController extends Controller {
AngelAuth auth; 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; serializer(User user) async => user.id;
/// Attempt to log a user in /// Attempt to log a user in
LocalAuthVerifier localVerifier(UserService userService) { LocalAuthVerifier localVerifier(Service userService) {
return (String username, String password) async { return (String username, String password) async {
List<User> users = await userService.index({ List<User> users = await userService.index({
'query': {'username': username} 'query': {'username': username}
@ -32,8 +37,8 @@ class AuthController extends Controller {
auth = new AngelAuth(jwtKey: app.jwt_secret) auth = new AngelAuth(jwtKey: app.jwt_secret)
..serializer = serializer ..serializer = serializer
..deserializer = deserializer ..deserializer = deserializer
..strategies.add(new LocalAuthStrategy( ..strategies
localVerifier(app.container.make(UserService)))); .add(new LocalAuthStrategy(localVerifier(app.service('api/users'))));
await super.call(app); await super.call(app);
await app.configure(auth); await app.configure(auth);
@ -41,9 +46,4 @@ class AuthController extends Controller {
@Expose('/local', method: 'POST') @Expose('/local', method: 'POST')
login() => auth.authenticate('local'); login() => auth.authenticate('local');
@Expose('/register', method: 'POST')
register(RequestContext req, UserService userService) async {
// And your registration logic...
}
} }

View file

@ -1,4 +1,5 @@
import 'package:angel_common/angel_common.dart'; import 'package:angel_common/angel_common.dart';
import 'package:angel_framework/hooks.dart' as hooks;
import 'package:crypto/crypto.dart' show sha256; import 'package:crypto/crypto.dart' show sha256;
import 'package:mongo_dart/mongo_dart.dart'; import 'package:mongo_dart/mongo_dart.dart';
import 'package:random_string/random_string.dart' as rs; import 'package:random_string/random_string.dart' as rs;
@ -8,11 +9,22 @@ export '../models/user.dart';
configureServer(Db db) { configureServer(Db db) {
return (Angel app) async { 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'); 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 service.beforeCreated
..listen(validateEvent(CREATE_USER)) ..listen(validateEvent(CREATE_USER))
..listen((e) { ..listen((e) {
@ -22,37 +34,12 @@ configureServer(Db db) {
hashPassword(e.data['password'], salt, app.jwt_secret) hashPassword(e.data['password'], salt, app.jwt_secret)
..['salt'] = salt; ..['salt'] = salt;
}); });
// Remove sensitive data from serialized JSON.
service.afterAll(hooks.remove(['password', 'salt']));
}; };
} }
/// SHA-256 hash any string, particularly a password. /// SHA-256 hash any string, particularly a password.
String hashPassword(String password, String salt, String pepper) => String hashPassword(String password, String salt, String pepper) =>
sha256.convert(('$salt:$password:$pepper').codeUnits).toString(); 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);
}
}