具体来说有点困难,但我会尝试为您提供一些关于如何在 Angular 中处理身份验证的提示。
Angular 附带的一些我关注这个主题的工具是:APP_INITIALIZER(上面有an article - 因为文档很少)、HttpInterceptor、LoadingComponent 或只是典型的 AppComponent。
在此过程中对我也有帮助的一些依赖项是 ngx-store 和 ngxs store。尽管名称相似,但它们是不同的工具。
我不会给你一个完整的回答你的问题,但一些提示:
例如,在身份验证服务中,您可以注册一个回调来监听某个正在修改的 cookie(感谢 ngx -store)。像这样:
constructor(public cookiesStorageService: CookiesStorageService,
@Inject(JWT_COOKIE_NAME) private _JWT_COOKIE_NAME: string) {
this.cookiesStorageService
.observe(this._JWT_COOKIE_NAME)
.subscribe((cookie: NgxStorageEvent) => this.checkIfNewToken(cookie.newValue));
}
请注意,上面为 JWT 令牌注入了 cookie 名称。我发现它更清晰并坚持角度原则:
export const JWT_COOKIE_NAME = new InjectionToken<string>('ACTUAL_JWT_COOKIE_NAME');
在上述情况下,如果您通过 cookie(不是身份验证标头)传递 JWT 令牌。
如果您确实传递了带有令牌的标头,则可以执行诸如拦截 HTTP 请求之类的操作。类似的东西:
@Injectable()
export class AuthenticationInterceptor implements HttpInterceptor {
constructor(private tokenExtractor: HttpXsrfTokenExtractor,
private authService: AuthenticationService,
@Inject(API_ENDPOINT) private _API_ENDPOINT: string) {
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (req.url.match(this._API_ENDPOINT)) {
// this.authService.intercept$.next(req);
const XSRFTokenHeaderName = 'X-XSRF-TOKEN';
const XSRFToken = this.tokenExtractor.getToken() as string;
if (XSRFToken !== null && !req.headers.has(XSRFTokenHeaderName)) {
req = req.clone({headers: req.headers.set(XSRFTokenHeaderName, XSRFToken)});
}
req = req.clone();
return next.handle(req);
} else {
return next.handle(req).map(event => {
if (event instanceof HttpResponse) {
// do something with response like sending it to an authentication service
}
return event;
});
}
}
}
我留下处理 X-XSRF-TOKEN 的规范示例。
App 初始化程序可以执行诸如调度登录操作之类的操作 - 或者实际上直接调用身份验证服务方法(我喜欢使用 ngxs 存储来处理这类事情):
export function appRun(store: Store) {
return () =>
store
.dispatch(new Login())
.pipe(finalize(() => true)) // let the app handle errors after bootstrapped
.toPromise();
}
在加载组件或应用程序组件中有这样的东西:
constructor(
private router: Router,
private actions$: Actions
) {}
ngOnInit() {
this.actions$
.pipe(ofActionErrored(Login))
.subscribe(() => this.router.navigate([Routes.PUBLIC]));
this.actions$
.pipe(ofActionSuccessful(Logout))
.subscribe(() => this.router.navigate([Routes.PUBLIC]));
}
NGXS 附带了操作成功或错误操作的有用处理程序,您可以使用这些处理程序在某处路由(上述路由在枚举中定义)。
因此,我在此响应中留下了许多步骤(例如声明状态、注册 APP_INITIALIZER、拦截器,...),但如果您认为评论有助于了解更多信息,请随意。
提到的库非常强大,可以帮助您以不同的方式解决问题(或者最终可能只是开销 - 只是一个存储某些状态的服务和一个拦截器可能就足够了)。
这不是很具体,但我认为这是一组很好的提示,可以帮助您继续前进。
编辑:我忘记了路线守卫。它们还可以帮助在 Angular 中进行身份验证。 CanLoad(用于延迟加载的模块)和 CanActivate 尤其是守卫。类似的东西:
canActivateRead(): Observable<boolean> | boolean {
const perm = this.store.selectSnapshot(state => state.module.acl);
if (perm) {
return this.canRead(perm);
} else {
return this.fetchACLAndTestPermission('READ');
}
}
private fetchACLAndTestPermission(perm: 'READ' | 'CREATE' | 'UPDATE'): Observable<boolean> {
return this.authService.getPermissionForACL('ACL').pipe(
tap(permission => this.store.dispatch(new SetMainACL({ permission }))),
map(perm => this.canRead(perm)),
tap(isPermitted => (isPermitted ? isPermitted : this.feedback.notAllowed()))
);
}
你可以继承到一个守卫服务:
@Injectable({
providedIn: 'root'
})
export class ParameterBaseGuard extends ParameterGuards implements CanLoad {
constructor(public authService: AuthenticationService, public feedback: FeedbackService, public store: Store) {
super(authService, feedback, store);
}
canLoad(): Observable<boolean> | Promise<boolean> | boolean {
return this.fetchACLAndTestPermission('READ');
}
canActivate(): Observable<boolean> | Promise<boolean> | boolean {
return this.canActivateRead();
}
}