认证管理器会将真正的认证任务委派给认证提供者,您也可以自定义认证提供者,只需要实现接口 AuthenticationProvider,并以 AuthenticationProvider 接口为 id 注入到 IoC 容器即可。
定义
export interface AuthenticationProvider {readonly priority: number;authenticate(): Promise<Authentication>;support(): Promise<boolean>;}
support 方法往往是匹配当前请求的路由是否为我们指定的即可。示例如下:
async support(): Promise<boolean> {return !!await this.requestMatcher.match(this.options.loginUrl, this.options.loginMethod);}
默认实现
@Component(AuthenticationProvider)export class AuthenticationProviderImpl implements AuthenticationProvider {@Value('malagu.security')protected readonly options: any;@Autowired(PasswordEncoder)protected readonly passwordEncoder: PasswordEncoder;@Autowired(UserStore)protected readonly userStore: UserStore;@Autowired(UserChecker)protected readonly userChecker: UserChecker;@Autowired(RequestMatcher)protected readonly requestMatcher: RequestMatcher;priority = DEFAULT_AUTHENTICATION_PROVIDER__PRIORITY;async authenticate(): Promise<Authentication> {const username = this.doGetValue(this.options.usernameKey);const password = this.doGetValue(this.options.passwordKey);if (!password || !username) {throw new BadCredentialsError('Bad credentials');}const user = await this.userStore.load(username);await this.userChecker.check(user);if (!await this.passwordEncoder.matches(password, user.password)) {throw new BadCredentialsError('Bad credentials');}Context.getResponse().statusCode = 302;Context.getResponse().setHeader('Location', this.options.loginSuccessUrl);return {principal: user,credentials: '',policies: user.policies,authenticated: true};}protected doGetValue(key: string): string {const request = Context.getRequest();if (request.body) {return request.body[key];} else {return request.query[key];}}async support(): Promise<boolean> {return !!await this.requestMatcher.match(this.options.loginUrl, this.options.loginMethod);}}
