Angular+adal.js会话过期时如何重定向至登录页(解决CORS报错)
解决Adal.js会话过期时CORS报错并自动重定向到登录页的问题
问题分析
你遇到的CORS错误根源在于:会话过期后,Adal.js默认会尝试通过跨域请求去获取新令牌,但Azure AD的授权端点本身不支持CORS,导致浏览器拦截这个请求并抛出错误。要解决这个问题,我们需要让Adal.js在检测到令牌过期时直接触发登录页重定向,而非发起这个无效的跨域请求。
解决方案步骤
1. 调整Adal核心配置参数
你的现有配置已经具备基础框架,我们需要优化几个关键参数,并补充主动处理逻辑:
- 保留
expireOffsetSeconds: 600:提前10分钟检测令牌过期,给重定向流程预留缓冲时间 - 将
navigateToLoginRequestUrl设为true:登录成功后自动跳回用户之前访问的页面(如果不需要该行为可保持false) - 核心思路:通过Adal的服务方法主动触发登录,替代默认的跨域令牌请求逻辑
2. 用路由守卫提前拦截未授权访问
在Angular的CanActivate路由守卫中,提前检查用户认证状态,一旦发现会话过期,直接触发登录重定向:
import { Injectable } from '@angular/core'; import { CanActivate, Router } from '@angular/router'; import { AdalService } from 'adal-angular'; @Injectable() export class AuthGuard implements CanActivate { constructor(private adalService: AdalService, private router: Router) {} canActivate(): boolean { const isAuthenticated = this.adalService.userInfo.authenticated; // 直接判断是否已认证 if (!isAuthenticated) { this.adalService.login(); return false; } // 额外检查令牌是否即将过期(基于你配置的expireOffsetSeconds) const tokenExpiration = this.adalService.getTokenExpiration(this.adalService.config.clientId); const now = new Date().getTime(); if (tokenExpiration - now < this.adalService.config.expireOffsetSeconds * 1000) { this.adalService.login(); return false; } return true; } }
3. 拦截API请求的401错误
如果用户在会话过期后发起API请求,服务器会返回401状态码,此时在HTTP拦截器中捕获该错误并触发登录:
import { Injectable } from '@angular/core'; import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpErrorResponse } from '@angular/common/http'; import { Observable, throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; import { AdalService } from 'adal-angular'; @Injectable() export class AdalInterceptor implements HttpInterceptor { constructor(private adalService: AdalService) {} intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { // 给API请求附加Bearer令牌 const token = this.adalService.getToken(this.adalService.config.clientId); if (token) { request = request.clone({ setHeaders: { Authorization: `Bearer ${token}` } }); } return next.handle(request).pipe( catchError((error: HttpErrorResponse) => { // 捕获401错误,清理缓存并跳转登录 if (error.status === 401) { this.adalService.clearCache(); this.adalService.login(); } return throwError(error); }) ); } }
4. 更新后的Adal配置代码
调整后的配置保留原有核心项,确保端点映射正确:
export function getAdalConfig() { return { tenant: 'de08ccD7-19b9-427d-9fe8-edf254300ca7', clientId: '828002a4-149f-478c-a318-933ad52ererf', redirectUri: window.location.origin, endpoints: { "https://xxx.azurewebsites.net/api/":"828002a4-149f-478c-a318-233456" }, navigateToLoginRequestUrl: true, // 登录后自动返回原请求页面 cacheLocation: 'localStorage', expireOffsetSeconds: 600 }; }
关键说明
- 主动调用
adalService.login()会直接重定向到Azure AD登录页,完全规避了Adal默认发起的跨域请求,从根源上解决CORS报错 - 路由守卫实现了"前置拦截",在用户访问受保护路由时就提前处理过期情况,提升体验
- HTTP拦截器覆盖了"已进入页面后发起请求"的场景,确保所有未授权请求都会触发登录跳转
内容的提问来源于stack exchange,提问作者3gwebtrain
相关产品推荐
相关产品推荐

