我实际上是在尝试确切地了解所有方法,实际上,身份验证的逻辑是这样。
1)用户转到有角度的应用程序,单击登录并获得重定向以使用这样的URL模式(以我的有角度的应用程序作为参数)登录: cas-example.com/login?service=my-angular-app
2)如果用户使用URL中的服务票证登录cas重定向到有角度的应用程序,则应如下所示:my-angular-app.com/?ticket=ST-1232431
3)将票证发送到后端后,如果票证有效,则后端会向我发送一个jwt,我可以在其中登录用户
这种方法好吗?我应该如何从故障单中实现侦听器,应该检查重定向是否来自cas并检查URL,还是始终检查URL?
答案 0 :(得分:0)
很难具体说明,但我将尝试为您提供一些有关如何在angular中处理身份验证的提示。
Angular附带的一些我专注于此主题的工具是:APP_INITIALIZER(an article,因为文档稀疏),HttpInterceptor,LoadingComponent或只是典型的AppComponent。< / p>
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初始化程序可以执行类似分派Login操作的操作-或实际上直接调用身份验证服务方法(我喜欢将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附带了动作成功或动作错误的有用处理程序,可用于在某个地方进行路由(上面的路由在Enum中定义)。
因此,我在此响应中遗漏了很多步骤(例如声明状态,注册APP_INITIALIZER,Interceptor等),但是如果您认为它有助于评论更多信息,请放心。 提到的库非常强大,可以帮助您以不同的方式解决问题(或者可能最终只是开销-仅存储一些状态的服务和拦截器就足够了)。 这不是很具体,但是我认为这是使您前进的一组不错的技巧。
edit:我忘记了路线守卫。他们还可以帮助您进行角度认证。 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();
}
}