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

如何在.NET 4.8 Web Forms应用(C#5)中集成Microsoft Azure AD SSO

在.NET 4.8 Web Forms应用中实现Azure AD SSO并保留传统登录的方案

核心结论:无需单独创建认证应用

直接在现有Web Forms应用内集成即可,独立认证应用会增加架构复杂度,完全没必要。以下是标准实现步骤和最佳实践:

步骤1:安装必备NuGet包

在NuGet包管理器中安装以下包:

  • Microsoft.Owin.Security.OpenIdConnect
  • Microsoft.Owin.Security.Cookies
  • Microsoft.Owin.Host.SystemWeb

步骤2:添加OWIN启动类

在项目根目录创建Startup.cs,配置Cookie认证和Azure AD OpenID Connect认证:

using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Owin;
using System.Configuration;
using System.Security.Claims;

[assembly: OwinStartup(typeof(YourAppNamespace.Startup))]
namespace YourAppNamespace
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // 启用Cookie认证,存储Azure AD登录后的用户凭证
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = "Cookies",
                LoginPath = new PathString("/Login.aspx")
            });

            // 配置Azure AD OpenID Connect认证
            app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
            {
                ClientId = ConfigurationManager.AppSettings["AzureADClientId"],
                Authority = $"https://login.microsoftonline.com/{ConfigurationManager.AppSettings["AzureADTenantId"]}/v2.0",
                RedirectUri = ConfigurationManager.AppSettings["AzureADRedirectUri"],
                PostLogoutRedirectUri = ConfigurationManager.AppSettings["AzureADPostLogoutRedirectUri"],
                Scope = "openid profile email",
                ResponseType = "id_token",

                // 认证成功后的回调处理
                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    AuthenticationValidated = n =>
                    {
                        // 获取Azure AD返回的用户核心信息
                        var email = n.AuthenticationTicket.Identity.FindFirst(ClaimTypes.Email)?.Value;
                        var fullName = n.AuthenticationTicket.Identity.FindFirst(ClaimTypes.Name)?.Value;

                        // 同步用户到现有系统:按邮箱匹配,无则创建关联账号
                        // 示例:var existingUser = UserRepository.GetByEmail(email);
                        // if (existingUser == null) UserRepository.Create(email, fullName);

                        // 自定义Claim,方便业务页面调用
                        n.AuthenticationTicket.Identity.AddClaim(new Claim("FullName", fullName));

                        return System.Threading.Tasks.Task.CompletedTask;
                    },
                    AuthenticationFailed = n =>
                    {
                        // 处理认证失败,跳转至错误页
                        n.HandleResponse();
                        n.Response.Redirect($"/Error.aspx?msg={Uri.EscapeDataString(n.Exception.Message)}");
                        return System.Threading.Tasks.Task.CompletedTask;
                    }
                }
            });
        }
    }
}

步骤3:配置Web.config参数

在Web.config的<appSettings>中添加Azure AD配置项:

<appSettings>
  <!-- Azure AD应用注册信息 -->
  <add key="AzureADClientId" value="你的应用注册ClientId" />
  <add key="AzureADTenantId" value="你的租户ID" />
  <add key="AzureADRedirectUri" value="https://你的域名/Login.aspx" />
  <add key="AzureADPostLogoutRedirectUri" value="https://你的域名/" />
</appSettings>

保留原有传统Forms认证配置(若之前存在):

<system.web>
  <authentication mode="Forms">
    <forms loginUrl="~/Login.aspx" timeout="2880" />
  </authentication>
</system.web>

步骤4:改造登录页面(Login.aspx)

保留原有邮箱密码表单,新增Azure AD登录按钮:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Login.aspx.cs" Inherits="YourAppNamespace.Login" %>

<!DOCTYPE html>
<html>
<head>
    <title>账号登录</title>
</head>
<body>
    <!-- 传统登录区域 -->
    <div class="login-section">
        <h3>账号密码登录</h3>
        <asp:TextBox ID="txtEmail" runat="server" placeholder="请输入邮箱"></asp:TextBox>
        <asp:TextBox ID="txtPassword" runat="server" TextMode="Password" placeholder="请输入密码"></asp:TextBox>
        <asp:Button ID="btnTraditionalLogin" runat="server" Text="登录" OnClick="btnTraditionalLogin_Click" />
    </div>

    <!-- Azure AD登录区域 -->
    <div class="sso-section">
        <h3>Microsoft账号登录</h3>
        <asp:Button ID="btnAzureADLogin" runat="server" Text="使用Microsoft账号登录" OnClick="btnAzureADLogin_Click" />
    </div>
</body>
</html>

登录页面后台逻辑(Login.aspx.cs):

using System;
using System.Web.Security;
using Microsoft.Owin.Security;

namespace YourAppNamespace
{
    public partial class Login : System.Web.UI.Page
    {
        // 传统登录逻辑(复用原有验证代码)
        protected void btnTraditionalLogin_Click(object sender, EventArgs e)
        {
            bool isValid = AuthService.ValidateCredentials(txtEmail.Text, txtPassword.Text);
            if (isValid)
            {
                FormsAuthentication.SetAuthCookie(txtEmail.Text, false);
                Response.Redirect("~/Default.aspx");
            }
            else
            {
                // 登录失败提示,比如用Label显示错误信息
            }
        }

        // 触发Azure AD SSO流程
        protected void btnAzureADLogin_Click(object sender, EventArgs e)
        {
            HttpContext.GetOwinContext().Authentication.Challenge(
                new AuthenticationProperties { RedirectUri = "~/Default.aspx" },
                OpenIdConnectAuthenticationDefaults.AuthenticationType);
        }
    }
}

步骤5:页面授权与用户信息获取

对需要登录的页面,可继续使用[Authorize]属性,两种登录方式的用户都能通过验证:

using System.Security.Claims;

namespace YourAppNamespace
{
    [System.Web.Mvc.Authorize]
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (User.Identity.IsAuthenticated)
            {
                // 获取用户信息:传统登录取Identity.Name,Azure AD登录取自定义Claim
                var currentUser = User.Identity.Name;
                var fullName = ((ClaimsIdentity)User.Identity).FindFirst("FullName")?.Value ?? currentUser;
                lblWelcome.Text = $"欢迎,{fullName}";
            }
        }
    }
}

步骤6:注销功能实现

确保同时清除Forms认证Cookie和Azure AD会话:

<asp:Button ID="btnLogout" runat="server" Text="注销" OnClick="btnLogout_Click" />

后台注销逻辑:

protected void btnLogout_Click(object sender, EventArgs e)
{
    // 清除传统Forms认证Cookie
    FormsAuthentication.SignOut();

    // 清除Azure AD认证Cookie并触发Azure AD端注销
    HttpContext.GetOwinContext().Authentication.SignOut(
        CookieAuthenticationDefaults.AuthenticationType,
        OpenIdConnectAuthenticationDefaults.AuthenticationType);

    Response.Redirect("~/Login.aspx");
}

最佳实践

  • 敏感信息管控:ClientId、TenantId等敏感信息不要硬编码,优先用Web.config配置或Azure Key Vault管理。
  • 强制HTTPS:Azure AD要求回调地址必须为HTTPS,部署到IIS时务必启用HTTPS并配置强制跳转规则。
  • 用户同步策略:以邮箱作为唯一标识,确保Azure AD用户能与现有系统账号关联,避免重复创建。
  • 异常兜底:在AuthenticationFailed回调中处理认证失败场景,给用户清晰的错误提示。
  • 测试覆盖:分别验证传统登录、Azure AD登录、注销流程,确保两种认证方式互不影响。
  • 权限扩展:若需角色权限控制,可在Azure AD应用中配置角色,通过Claim读取角色信息实现授权。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 15:58:10