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

Azure App Service中ASP.NET Core MVC扩展MicrosoftIdentityWebAppAuthentication实现弹窗认证

实现ASP.NET Core MVC应用的弹窗式Azure AD认证

可以通过前端MSAL.js弹窗获取身份令牌 + 后端验证令牌并创建会话的混合方案实现,完全保留现有AddMicrosoftIdentityWebAppAuthentication的后端流程,无需重构整个项目。以下是具体实现步骤:


1. 前端添加MSAL.js弹窗登录逻辑

在你的MVC视图(比如共享布局页_Layout.cshtml或自定义登录页)中引入MSAL.js,并编写弹窗登录的触发代码:

<!-- 引入MSAL.js -->
<script src="https://alcdn.msauth.net/browser/2.38.1/js/msal-browser.min.js"></script>

<script>
    // 从后端配置读取Azure AD参数(也可直接填入应用注册信息)
    const msalConfig = {
        auth: {
            clientId: '@Configuration["AzureAd:ClientId"]',
            authority: '@Configuration["AzureAd:Authority"]',
            redirectUri: `${window.location.origin}/auth/popup-callback`
        }
    };

    const msalInstance = new msal.PublicClientApplication(msalConfig);

    // 弹窗登录触发函数
    async function triggerPopupLogin() {
        try {
            // 弹窗发起认证,获取id token
            const loginResult = await msalInstance.loginPopup({
                scopes: ["openid", "profile", "user.read"]
            });

            // 将id token传给后端验证并创建会话
            const validateResponse = await fetch('/auth/validate-token', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ idToken: loginResult.idToken.rawIdToken })
            });

            if (validateResponse.ok) {
                // 会话创建成功,刷新页面或跳转至目标页
                window.location.reload();
            }
        } catch (err) {
            console.error('弹窗登录失败:', err);
            alert('登录出错,请重试');
        }
    }
</script>

<!-- 替换原有的登录按钮 -->
<button onclick="triggerPopupLogin()" class="btn btn-primary">弹窗登录</button>

2. 后端添加令牌验证与会话创建接口

新增一个API控制器,用于接收前端传来的id token,验证其有效性后创建ASP.NET Core用户会话:

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;

[ApiController]
[Route("auth")]
public class AuthPopupController : ControllerBase
{
    private readonly IConfiguration _config;
    private readonly ILogger<AuthPopupController> _logger;

    public AuthPopupController(IConfiguration config, ILogger<AuthPopupController> logger)
    {
        _config = config;
        _logger = logger;
    }

    // 允许匿名访问,接收前端传来的id token
    [AllowAnonymous]
    [HttpPost("validate-token")]
    public async Task<IActionResult> ValidatePopupToken([FromBody] TokenRequest request)
    {
        if (string.IsNullOrEmpty(request.IdToken))
            return BadRequest("令牌不能为空");

        try
        {
            // 配置令牌验证参数
            var validationParams = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidIssuer = _config["AzureAd:Authority"],
                ValidateAudience = true,
                ValidAudience = _config["AzureAd:ClientId"],
                ValidateLifetime = true,
                IssuerSigningKeys = await GetSigningKeysAsync(_config["AzureAd:Authority"])
            };

            // 验证令牌并生成ClaimsPrincipal
            var handler = new JwtSecurityTokenHandler();
            ClaimsPrincipal userPrincipal = handler.ValidateToken(request.IdToken, validationParams, out _);

            // 创建Cookie会话,和原有认证流程共享会话机制
            await HttpContext.SignInAsync(
                CookieAuthenticationDefaults.AuthenticationScheme,
                userPrincipal,
                new AuthenticationProperties { IsPersistent = false });

            return Ok();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "令牌验证失败");
            return BadRequest("无效的身份令牌");
        }
    }

    // 弹窗回调页面(MSAL弹窗完成后会跳转至此,可直接关闭)
    [AllowAnonymous]
    [Route("popup-callback")]
    public IActionResult PopupCallback()
    {
        return Content("登录完成,请关闭此窗口");
    }

    // 辅助方法:获取Azure AD的签名密钥
    private async Task<IEnumerable<SecurityKey>> GetSigningKeysAsync(string authority)
    {
        var configManager = new ConfigurationManager<OpenIdConnectConfiguration>(
            $"{authority}/.well-known/openid-configuration",
            new OpenIdConnectConfigurationRetriever());
        var config = await configManager.GetConfigurationAsync(CancellationToken.None);
        return config.SigningKeys;
    }
}

// 接收前端令牌的请求模型
public class TokenRequest
{
    public string IdToken { get; set; }
}

3. 调整Azure AD应用注册配置

在Azure门户的应用注册中,添加前端配置的redirectUri(比如https://your-app.azurewebsites.net/auth/popup-callback或本地测试地址),并确保应用注册允许公共客户端流(在"身份验证" -> "高级设置"中开启"允许公共客户端流")。


4. 保留原有认证流程的兼容性

你的现有Startup.cs代码无需大幅修改,AddMicrosoftIdentityWebAppAuthentication已经默认配置了Cookie认证,两种登录模式会共享同一个会话机制。如果需要同时保留原有的重定向登录模式,只需保留原有的登录入口即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 08:23:07