认证管理器会将真正的认证任务委派给认证提供者,您也可以自定义认证提供者,只需要实现接口 AuthenticationProvider,并以 AuthenticationProvider 接口为 id 注入到 IoC 容器即可。

定义

  1. export interface AuthenticationProvider {
  2. readonly priority: number;
  3. authenticate(): Promise<Authentication>;
  4. support(): Promise<boolean>;
  5. }

support 方法往往是匹配当前请求的路由是否为我们指定的即可。示例如下:

  1. async support(): Promise<boolean> {
  2. return !!await this.requestMatcher.match(this.options.loginUrl, this.options.loginMethod);
  3. }

默认实现

  1. @Component(AuthenticationProvider)
  2. export class AuthenticationProviderImpl implements AuthenticationProvider {
  3. @Value('malagu.security')
  4. protected readonly options: any;
  5. @Autowired(PasswordEncoder)
  6. protected readonly passwordEncoder: PasswordEncoder;
  7. @Autowired(UserStore)
  8. protected readonly userStore: UserStore;
  9. @Autowired(UserChecker)
  10. protected readonly userChecker: UserChecker;
  11. @Autowired(RequestMatcher)
  12. protected readonly requestMatcher: RequestMatcher;
  13. priority = DEFAULT_AUTHENTICATION_PROVIDER__PRIORITY;
  14. async authenticate(): Promise<Authentication> {
  15. const username = this.doGetValue(this.options.usernameKey);
  16. const password = this.doGetValue(this.options.passwordKey);
  17. if (!password || !username) {
  18. throw new BadCredentialsError('Bad credentials');
  19. }
  20. const user = await this.userStore.load(username);
  21. await this.userChecker.check(user);
  22. if (!await this.passwordEncoder.matches(password, user.password)) {
  23. throw new BadCredentialsError('Bad credentials');
  24. }
  25. Context.getResponse().statusCode = 302;
  26. Context.getResponse().setHeader('Location', this.options.loginSuccessUrl);
  27. return {
  28. principal: user,
  29. credentials: '',
  30. policies: user.policies,
  31. authenticated: true
  32. };
  33. }
  34. protected doGetValue(key: string): string {
  35. const request = Context.getRequest();
  36. if (request.body) {
  37. return request.body[key];
  38. } else {
  39. return request.query[key];
  40. }
  41. }
  42. async support(): Promise<boolean> {
  43. return !!await this.requestMatcher.match(this.options.loginUrl, this.options.loginMethod);
  44. }
  45. }