Нема описа
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http';
  2. import { inject } from '@angular/core';
  3. import { Router } from '@angular/router';
  4. import { catchError, throwError } from 'rxjs';
  5. import { AuthService } from '../services/auth.service';
  6. // 防重复重定向机制
  7. let lastRedirectTime = 0;
  8. const REDIRECT_DEBOUNCE_MS = 1000;
  9. export const AuthInterceptor: HttpInterceptorFn = (req, next) => {
  10. const router = inject(Router);
  11. const authService = inject(AuthService);
  12. console.log(`拦截请求: ${req.method} ${req.url}`);
  13. // 克隆请求以添加认证头
  14. let authReq = req;
  15. // 检查是否为公开端点(不需要认证)
  16. const isPublicEndpoint = req.url.includes('/auth/login') || req.url.includes('/auth/health');
  17. // 为需要认证的API请求添加Bearer认证头
  18. if (req.url.includes('/api/') && !isPublicEndpoint) {
  19. const token = authService.getAuthToken();
  20. console.log(`🔍 [AuthInterceptor] 处理API请求: ${req.method} ${req.url}`);
  21. console.log(`🔍 [AuthInterceptor] Token存在: ${!!token}, 长度: ${token?.length}`);
  22. if (token) {
  23. console.log('🔍 [AuthInterceptor] API请求,添加Bearer认证头');
  24. authReq = req.clone({
  25. setHeaders: {
  26. Authorization: `Bearer ${token}`
  27. }
  28. });
  29. console.log(`🔍 [AuthInterceptor] 添加后的请求头:`, authReq.headers.get('Authorization')?.substring(0, 30) + '...');
  30. } else {
  31. console.warn('🔍 [AuthInterceptor] API请求需要认证,但用户未登录,不添加认证头');
  32. // 不添加认证头,后端会返回401错误,错误处理会跳转到登录页
  33. }
  34. } else {
  35. console.log('🔍 [AuthInterceptor] 公开端点或非API请求,不添加认证头');
  36. }
  37. return next(authReq).pipe(
  38. catchError((error: HttpErrorResponse) => {
  39. console.log(`请求错误: ${error.status} ${req.method} ${req.url}`);
  40. console.log('错误详情:', error.error);
  41. // 处理认证错误
  42. if (error.status === 401 || error.status === 403 ||
  43. (error.error && (error.error.error?.includes('认证') || error.error.error?.includes('缺少认证')))) {
  44. console.warn('认证失败,跳转到登录页面:', error.error);
  45. console.log('当前路由:', router.url);
  46. // 清除本地存储的认证信息
  47. authService.logout();
  48. // 跳转到登录页面,除非当前已经在登录页面
  49. if (!router.url.includes('/login')) {
  50. // 防重复重定向:检查上次重定向时间
  51. const now = Date.now();
  52. if (now - lastRedirectTime > REDIRECT_DEBOUNCE_MS) {
  53. lastRedirectTime = now;
  54. console.log('重定向到登录页面');
  55. router.navigate(['/login'], {
  56. queryParams: { returnUrl: router.url }
  57. });
  58. } else {
  59. console.log('跳过重复重定向(防抖期内)');
  60. }
  61. } else {
  62. console.log('已经在登录页面,不重定向');
  63. }
  64. }
  65. return throwError(() => error);
  66. })
  67. );
  68. };