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

基于.NET Web Forms的Entra ID SSO集成问题:本地登录验证优化

.NET Web Forms集成Entra ID SSO+本地MFA双登录实现方案

一、解决全局强制Entra ID登录问题

默认Visual Studio模板会将Entra ID认证设为全局默认,导致用户必须先走Entra ID登录。要保留本地MFA登录选项,需调整认证配置,让Entra ID认证仅在用户主动选择时触发:

  1. 修改web.config中的认证节点,默认使用Forms认证(对应本地会话),同时注册Entra ID的OpenID Connect认证方案:
<system.web>
  <authentication mode="Forms">
    <forms loginUrl="~/Account/Login" timeout="2880" />
  </authentication>
</system.web>
<system.webServer>
  <modules>
    <remove name="FormsAuthentication" />
    <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />
    <add name="OpenIdConnectAuthenticationModule" type="Microsoft.Owin.Security.OpenIdConnect.OpenIdConnectAuthenticationModule, Microsoft.Owin.Security.OpenIdConnect" />
  </modules>
</system.webServer>
  1. 在用户登录页面添加两个按钮:一个触发本地MFA登录,另一个触发Entra ID SSO跳转。触发Entra ID的按钮点击事件中,手动发起认证挑战:
protected void btnEntraLogin_Click(object sender, EventArgs e)
{
    HttpContext.Current.GetOwinContext().Authentication.Challenge(
        new AuthenticationProperties { RedirectUri = "~/Account/EntraCallback" },
        OpenIdConnectAuthenticationDefaults.AuthenticationType);
}

二、仅验证Entra ID响应,创建本地会话后清除Entra ID认证状态

要实现只验证Entra ID的SSO响应、不保留其认证状态,需手动处理回调流程:

  1. 创建回调页面(EntraCallback.aspx),在Page_Load中处理ID Token验证和本地会话创建:
protected void Page_Load(object sender, EventArgs e)
{
    var authResult = HttpContext.Current.GetOwinContext().Authentication.AuthenticateAsync(OpenIdConnectAuthenticationDefaults.AuthenticationType).Result;
    
    // 验证ID Token有效性(签名、过期时间、受众等)
    if (authResult == null || !authResult.Identity.IsAuthenticated)
    {
        Response.Redirect("~/Account/Login?error=EntraAuthFailed");
        return;
    }

    // 提取Entra ID用户信息(根据实际需求获取,比如邮箱、姓名)
    string userEmail = authResult.Identity.FindFirst(ClaimTypes.Email)?.Value;
    string userName = authResult.Identity.FindFirst(ClaimTypes.Name)?.Value;

    // 查询或创建本地用户档案(替换为你的业务逻辑)
    var localUser = GetOrCreateLocalUser(userEmail, userName);
    if (localUser == null)
    {
        Response.Redirect("~/Account/Login?error=UserNotFound");
        return;
    }

    // 创建本地Forms认证会话
    FormsAuthentication.SetAuthCookie(localUser.UserId.ToString(), false);

    // 清除Entra ID的认证票据,避免保留其登录状态
    HttpContext.Current.GetOwinContext().Authentication.SignOut(
        OpenIdConnectAuthenticationDefaults.AuthenticationType,
        CookieAuthenticationDefaults.AuthenticationType);

    // 跳转至应用首页或用户原访问页面
    Response.Redirect(FormsAuthentication.GetRedirectUrl(localUser.UserId.ToString(), false) ?? "~/");
}

// 示例:本地用户查询/创建逻辑
private LocalUser GetOrCreateLocalUser(string email, string name)
{
    // 替换为你的数据库操作逻辑
    using (var db = new AppDbContext())
    {
        var user = db.LocalUsers.FirstOrDefault(u => u.Email == email);
        if (user == null)
        {
            user = new LocalUser
            {
                Email = email,
                Name = name,
                CreatedDate = DateTime.Now
            };
            db.LocalUsers.Add(user);
            db.SaveChanges();
        }
        return user;
    }
}
  1. 调整OpenID Connect中间件配置(在Startup.Auth.cs中),禁用自动认证和自动重定向,仅处理回调:
public void ConfigureAuth(IAppBuilder app)
{
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = CookieAuthenticationDefaults.AuthenticationType
    });

    app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
    {
        ClientId = ConfigurationManager.AppSettings["EntraClientId"],
        Authority = $"https://login.microsoftonline.com/{ConfigurationManager.AppSettings["EntraTenantId"]}/v2.0",
        RedirectUri = ConfigurationManager.AppSettings["EntraRedirectUri"],
        ResponseType = OpenIdConnectResponseType.IdToken,
        Scope = "openid profile email",
        // 禁用自动触发认证,仅在手动Challenge时跳转
        AuthenticationMode = AuthenticationMode.Passive,
        // 禁用自动回调后登录,改为手动处理
        Notifications = new OpenIdConnectAuthenticationNotifications
        {
            RedirectToIdentityProvider = n =>
            {
                // 可选:自定义跳转逻辑
                return Task.FromResult(0);
            },
            MessageReceived = n =>
            {
                // 可选:处理消息接收逻辑
                return Task.FromResult(0);
            }
        }
    });
}

关键注意事项

  • 确保Entra ID应用注册中,重定向URI配置为回调页面的完整URL(如https://your-app.com/Account/EntraCallback.aspx)。
  • ID Token的验证必须严格,包括签名验证、过期时间检查、受众(Audience)匹配,避免伪造请求。
  • 本地用户档案的创建逻辑需要符合你的权限体系,确保同步Entra ID用户的必要信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 02:13:30