我是 Angular 18 的新手,我无法解决刷新令牌的实现,我的后端在 PostMan 工作正常,使用curl命令也可以,我发送带有刷新令牌的标头和后端响应带有 accessToken 的对象也可以正常工作,但是当我使用前端时,错误是 401!请帮助我,非常感谢!
这是拦截器
export const customInterceptor: HttpInterceptorFn = (req, next) => {
const excludedRoutes = ['/login']; // Customizable array
const shouldExclude = excludedRoutes.some(route => req.url.includes(route));
const authService = inject(AuthService);
if (shouldExclude) {
return next(req);
}
const token = authService.getAuthToken();
const cloneRequest = req.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
return next(cloneRequest).pipe(
catchError((error) => {
if (error.status === 401) {
console.log("From the interceptor, here is the error: " + error.status);
return authService.refreshToken().pipe(
switchMap((res) => {
localStorage.setItem('authToken', res.accessToken);
console.log("From the interceptor, the new authToken is: " + res.accessToken);
const newReq = req.clone({
setHeaders: {
Authorization: `Bearer ${res.accessToken}`
}
});
return next(newReq);
}),
catchError((refreshErr) => {
const finalError = new Error(refreshErr);
console.log("Error refreshing the token", finalError);
authService.logout();
return throwError(() => new Error('Session expired, please log in again'));
})
);
} else {
// Handle other errors (e.g., network errors)
return throwError(() => error);
}
})
);
};
这是服务方法:
refreshToken() {
const refreshToken = localStorage.getItem('refreshToken');
console.log("The refreshToken inside the method is: " + refreshToken);
if (!refreshToken) {
throw new Error('Refresh token missing');
}
console.log("Sending refresh token to backend: " + refreshToken);
return this._httpClient.post<any>(`${this.baseURL}/refresh`, {}, {
headers: {
Authorization: `Bearer ${refreshToken}`
}
}).pipe(
catchError((error) => {
console.error("Refresh token error:", error);
return throwError(() => new Error("Refresh error"));
})
);
}
您的 customInterceptor 似乎大部分设置正确,但可能有几个原因导致您在 Angular 前端收到 401 错误:
令牌同步问题:可能存在拦截器在获取新令牌后仍尝试使用旧令牌的问题。 拦截器链接问题:如果注册了多个拦截器,它们可能无法正确处理 401 错误,从而导致令牌刷新无法正确传播。 API 请求计时:在发出新请求之前,令牌刷新可能尚未完成。 Angular 的 HttpInterceptorFn 语法:如果您将 Angular 16+ 与 HttpInterceptorFn 函数类型一起使用,请确保正确实现设置。
尝试过这段代码:
export const customInterceptor: HttpInterceptorFn = (req, next) => {
const excludedRoutes = ['/login']; // Exclude login endpoint from interception
const shouldExclude = excludedRoutes.some(route => req.url.includes(route));
const authService = inject(AuthService);
if (shouldExclude) {
return next(req);
}
const token = authService.getAuthToken();
let cloneRequest = req;
if (token) {
cloneRequest = req.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
}
return next(cloneRequest).pipe(
catchError((error) => {
if (error.status === 401) {
// Token is expired or invalid, try refreshing the token
return authService.refreshToken().pipe(
switchMap((res) => {
// Store new access token
localStorage.setItem('authToken', res.accessToken);
// Clone the request with new token and resend it
const newReq = req.clone({
setHeaders: {
Authorization: `Bearer ${res.accessToken}`
}
});
// Continue the request with the new token
return next(newReq);
}),
catchError((refreshErr) => {
// Refresh token failed, handle logout or other error
console.log("Error refreshing the token:", refreshErr);
authService.logout(); // Redirect to login or handle logout
return throwError(() => new Error('Session expired, please log in again'));
})
);
} else {
// For any other errors
return throwError(() => error);
}
})
);
};
在 authService 中:
refreshToken() {
const refreshToken = localStorage.getItem('refreshToken');
console.log("The refreshToken inside the method is: " + refreshToken);
if (!refreshToken) {
throw new Error('Refresh token missing');
}
return this._httpClient.post<any>(`${this.baseURL}/refresh`, {}, {
headers: {
Authorization: `Bearer ${refreshToken}`
}
}).pipe(
catchError((error) => {
console.error("Refresh token error:", error);
return throwError(() => new Error("Refresh error"));
})
);
}