You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ADAL5 Angular未授权用户URL循环,需跳转至自定义错误页

解决Adal Angular5未授权用户循环跳转问题

我来帮你搞定这个URL循环跳转的问题!核心原因是你的Guard只判断了用户是否已认证,但没处理用户已登录但无应用权限的情况——当Azure AD返回access_denied(对应AADSTS50105错误)时,你的代码依然会触发登录跳转,导致AAD和你的应用之间反复重定向。

问题根源分析

当用户已登录但未被分配到应用的授权组/角色时,Azure AD会回调到你的应用,携带error=access_denied和error_description=AADSTS50105参数。但当前的AdalGuard只检查userInfo.authenticated:

  • 如果此时authenticated为false(Adal可能因为错误标记用户未认证),代码会调用login()再次跳转AAD;
  • AAD发现用户已登录但无权限,再次回调应用,形成循环。

解决方案:在Guard中处理访问拒绝错误

修改你的adal.guard.ts,添加对AAD错误参数的检测,当识别到access_denied时,直接跳转到自定义401错误页,避免触发登录跳转:

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Adal5Service } from 'adal-angular5';
import { environment } from '../environments/environment';
import { Router } from '@angular/router';

@Injectable()
export class AdalGuard implements CanActivate {
  constructor(private adal5Service: Adal5Service, private router: Router) {
    // 建议:把Adal初始化移到AppModule的APP_INITIALIZER中,避免每次Guard激活都重复初始化
    console.log("location below: ");
    if (location) console.log(location);
    else console.log("some falsy value");
    this.adal5Service.init({
      ...environment.ssoConfig,
      redirectUri: location.protocol + '//' + location.host + location.pathname
    });
  }

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    if (!environment.production) return true;

    this.Callback();

    // 解析URL Hash中的错误参数
    const hashParams = new URLSearchParams(window.location.hash.slice(1));
    const error = hashParams.get('error');
    const errorDescription = hashParams.get('error_description');

    // 识别Azure AD的"用户未分配应用角色"错误
    const isAccessDenied = error === 'access_denied' && errorDescription?.includes('AADSTS50105');

    if (isAccessDenied) {
      // 清除Hash中的错误参数,避免页面刷新后再次触发逻辑
      window.history.replaceState({}, document.title, window.location.pathname);
      // 跳转到自定义401错误页
      this.router.navigate(['error/401']);
      return false;
    }

    if (!this.adal5Service.userInfo.authenticated) {
      this.LogIn();
      return false;
    } else {
      return true;
    }
  }

  Callback() {
    this.adal5Service.handleWindowCallback();
  }

  LogIn() {
    this.adal5Service.login();
  }
}

关键注意事项

  1. 错误页路由需排除Guard保护
    确保你的401错误页路由不使用AdalGuard,否则会再次触发认证逻辑,导致新的循环:

    // app-routing.module.ts
    const routes: Routes = [
      { path: '', component: HomeComponent, canActivate: [AdalGuard] },
      { path: 'error/401', component: UnauthorizedComponent }, // 这里不要加canActivate
      // 其他业务路由...
    ];
    
  2. 优化Adal初始化逻辑
    把Adal的init从Guard构造函数移到APP_INITIALIZER中,确保初始化只执行一次:

    // app.module.ts
    import { APP_INITIALIZER } from '@angular/core';
    import { Adal5Service } from 'adal-angular5';
    import { environment } from '../environments/environment';
    
    // 定义初始化工厂函数
    export function adalInitializer(adalService: Adal5Service) {
      return () => {
        adalService.init({
          ...environment.ssoConfig,
          redirectUri: window.location.protocol + '//' + window.location.host + window.location.pathname
        });
      };
    }
    
    @NgModule({
      // ...其他配置
      providers: [
        Adal5Service,
        {
          provide: APP_INITIALIZER,
          useFactory: adalInitializer,
          deps: [Adal5Service],
          multi: true
        },
        AdalGuard
      ]
    })
    export class AppModule { }
    

这样修改后,未授权用户会被直接引导到自定义401错误页,彻底解决循环跳转问题。

内容的提问来源于stack exchange,提问作者Vista

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:28:03