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

Angular+ASP.NET MVC集成ADFS SSO:Challenge()无法打开ADFS页面

问题分析与解决方案

你的核心问题在于AJAX请求无法处理服务器返回的302重定向响应,同时结合代码和配置来看,还有几处细节需要调整,下面逐个拆解:


1. 为什么Authentication.Challenge()无法打开ADFS页面?

当Angular通过AJAX(HttpClient.post)调用IsLogedInRoled接口时,服务器执行Challenge()后会返回302重定向到ADFS登录页,但AJAX请求不会自动跳转到这个重定向地址——它只会把重定向的响应内容(ADFS登录页HTML)当成接口返回值,而非触发浏览器跳转。这是导致你看不到ADFS页面的根本原因。

解决方案:让前端触发浏览器跳转,而非在API内处理Challenge

修改API逻辑,仅返回认证状态,把触发SSO跳转的逻辑交给前端:

[HttpPost]
public bool IsLogedInRoled(NR role)
{
    if (User.Identity.IsAuthenticated)
    {
        if (!string.IsNullOrEmpty(role.role))
        {
            var isLogedInRoled = GetUserRoles().Select(x => x.ToLower()).Contains(role.role);
            return isLogedInRoled;
        }
        return true;
    }
    // 不再在这里执行Challenge,仅返回未认证状态
    return false;
}

然后新建一个MVC控制器的Action专门处理SSO跳转(让浏览器直接请求这个地址,而非AJAX):

public class AccountController : Controller
{
    public ActionResult Login(string returnUrl = "/")
    {
        if (!User.Identity.IsAuthenticated)
        {
            HttpContext.GetOwinContext().Authentication.Challenge(
                new AuthenticationProperties { RedirectUri = returnUrl },
                WsFederationAuthenticationDefaults.AuthenticationType);
            return new HttpUnauthorizedResult();
        }
        return Redirect(returnUrl);
    }
}

2. 调整Angular路由守卫的逻辑

当前AuthGuardService的异步处理存在问题,且未正确触发SSO跳转。修改为:

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { AuthService } from 'app/services/auth/auth.service';
import { Observable, of } from 'rxjs';
import { map, catchError } from 'rxjs/operators';

@Injectable()
export class AuthGuardService {
    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
        return this.auth.checkLogedinRole(route.data)
            .pipe(
                map(isAuthenticated => {
                    if (isAuthenticated) {
                        return true;
                    }
                    // 直接跳转到MVC的Login Action,触发ADFS SSO
                    window.location.href = `/Account/Login?returnUrl=${encodeURIComponent(state.url)}`;
                    return false;
                }),
                catchError(() => {
                    window.location.href = `/Account/Login?returnUrl=${encodeURIComponent(state.url)}`;
                    return of(false);
                })
            );
    }
    constructor(private router: Router, private auth: AuthService) { }
}

3. 优化Owin中间件配置

你的Startup.cs中中间件顺序和细节可以调整,确保Umbraco和自定义认证逻辑不冲突:

public class CustomeStartup : UmbracoDefaultOwinStartup
{
    private static string realm = ConfigurationManager.AppSettings["ida:Wtrealm"];
    private static string adfsMetadata = ConfigurationManager.AppSettings["ida:ADFSMetadata"];
    private static string adfsWreply = ConfigurationManager.AppSettings["ida:Wreply"];

    public override void Configuration(IAppBuilder app)
    {
        // 先加载Umbraco的默认Owin配置
        base.Configuration(app);

        // 配置Cookie认证
        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
        app.UseCookieAuthentication(new CookieAuthenticationOptions 
        { 
            CookieName = "E-services",
            // 可选:设置Cookie的过期时间、安全属性等
            ExpireTimeSpan = TimeSpan.FromHours(8),
            CookieSecure = CookieSecureOption.Always
        });

        // 配置WsFederation认证
        app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions
        {
            Wtrealm = realm,
            MetadataAddress = adfsMetadata,
            Notifications = new WsFederationAuthenticationNotifications()
            {
                SecurityTokenValidated = context =>
                {
                    ClaimsIdentity identity = context.AuthenticationTicket.Identity;
                    string[] roles = NParser.ToDecimal(identity.Name) > 0 ? new[] { "Student" } : new[] { "Employee" };
                    identity.AddClaim(new Claim(ClaimTypes.Role, roles.First()));
                    return Task.CompletedTask; // 用更规范的Task.CompletedTask代替Task.FromResult(0)
                },
                RedirectToIdentityProvider = context =>
                {
                    context.ProtocolMessage.Wreply = adfsWreply;
                    return Task.CompletedTask;
                }
            },
        });

        app.UseStageMarker(PipelineStage.Authenticate);
    }
}

4. 验证ADFS信赖方配置

确保ADFS服务器上的信赖方设置与你的Web.config一致:

  • ida:Wtrealm必须和ADFS信赖方的标识符完全匹配(包括末尾的斜杠)
  • ida:Wreply必须在ADFS信赖方的允许回复URL列表中
  • 确保服务器能正常访问ADFS元数据地址(ida:ADFSMetadata)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:35:50