Angular:在拦截器中添加不记名令牌

问题描述 投票:0回答:4

我正在使用 Angular + AWS Cognito

我能够登录并需要添加认知不记名令牌

@Injectable({
providedIn: 'root',
})
export class InterceptorService implements HttpInterceptor {
constructor(public loaderService: LoaderService, private router: Router) { }

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return this.getToken().pipe(
        mergeMap((token) => {
            request = request.clone(
                {
                    setHeaders: { Authorization: `Bearer ${token}` }
                });

            return next.handle(request);
        })
    );
}

getToken() {
    return from(
        new Promise((resolve, reject) => {
            Auth.currentSession().then((session) => {
                if (!session.isValid()) {
                    resolve(null);
                } else {
                    resolve(session.getIdToken().getJwtToken());
                }
            }).catch(err => { return resolve(null) });
        })
    );
}
}

这段代码工作正常,问题是这里如何处理 HttpResponse?

我尝试了以下代码,但它不起作用,请求没有承载令牌

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return next.handle(request).pipe(
            tap(
            (event) => {
                if (event instanceof HttpResponse) {
                    if (event.status !== 200) {
                        console.log('Response', event.status);
                    }
                } else {
                    return this.getToken().pipe(
                       mergeMap((token) => {
                            request = request.clone(
                                {
                                    setHeaders: { Authorization: `Bearer ${token}` }
                                });

                            return next.handle(request);
                        })
                    );
                }
            },
            (error) => {
                 // to handle errors
            }
        )
}
angular angular-http-interceptors
4个回答
0
投票

据我所知,

tap
仅在没有错误时运行。如果您希望函数在出现错误时运行,则必须在管道中使用
catchError()


0
投票

tap 是产生副作用的运算符,你不能只从回调中返回 observable,它不会被订阅。另外,发送原始请求并在失败时使用令牌重试的逻辑有点奇怪。我相信你应该为每个请求添加令牌。

intercept(...) {
  return this.sendWithToken(request).pipe(
    catchError(error => error.status === 401 ? this.sendWithToken(request) : throwError(error)) // try one more time if return code is 401 
  );
}

sendWithToken(request: ...) {
  return this.getToken().pipe(
    mergeMap(token => addToken(request)),
    mergeMap(authedRequest => next.handle(authedRequest)),
  );
}

getToken 代码也可以改进,因为如果你已经有一个承诺,则不需要创建承诺

getToken() {
    return from(
        Auth.currentSession().then((session) => {
            if (!session.isValid()) {
                return null;
            } else {
                return session.getIdToken().getJwtToken();
            }
        }).catch(err => null);
    );
}

0
投票

我用以下拦截器代码解决了这个问题:

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return this.getToken().pipe(
        mergeMap((token) => {
            request = request.clone(
                {
                    headers: request.headers.set('Authorization', `Bearer ${token}`)
                });

            return next.handle(request).pipe(
                tap(evt => {
                      // modify here
                }),
                catchError((error: any) => {
                    if (error && error.status) {
                        if (error.status == 401) {
                            this.router.navigate(['/']);
                        }
                    } else {
                        return throwError(error);
                    }
                })
            )
        })
    );
}

getToken() {
    return from(
        Auth.currentSession().then((session) => {
            if (!session.isValid()) {
                return null;
            } else {
                return session.getIdToken().getJwtToken();
            }
        }).catch(err => null)
    );
}

0
投票

对于

@angular/cli
17+ 和
aws-amplify
v6,我必须采用这样的解决方案来注入令牌:

import { HttpEvent, HttpHandlerFn, HttpRequest } from '@angular/common/http'
import { fetchAuthSession } from 'aws-amplify/auth'
import { from, Observable, switchMap } from 'rxjs'

export function tokenInjectionInterceptor(
    req: HttpRequest<unknown>,
    next: HttpHandlerFn
): Observable<HttpEvent<unknown>> {
    return from(getAuthToken()).pipe(
        switchMap((token: any) => {
            if (token) {
                const authReq = req.clone({
                    setHeaders: { Authorization: `Bearer ${token}` },
                })
                return next(authReq)
            } else {
                return next(req)
            }
        })
    )
}

async function getAuthToken(): Promise<string | null> {
    try {
        const session = await fetchAuthSession()
        const tokens: any = await session?.tokens
        return tokens?.accessToken?.toString()
    } catch (error) {
        console.error('Error fetching auth token:', error)
        return null
    }
}



© www.soinside.com 2019 - 2024. All rights reserved.