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

基于Microsoft.Identity.Web在State参数中设置不同ReturnUrl的技术问题

Microsoft.Identity.Web 中自定义state参数实现多租户跳转方案

Microsoft.Identity.Web 原生支持扩展OpenID Connect事件来自定义state参数,无需修改底层认证逻辑,具体实现步骤如下:

前置配置

你需要先在Azure AD门户配置全局共享的重定向URI,比如https://login.myapp.com/signin-oidc,所有子域名的认证请求都统一用这个地址作为回调地址。

1. 注入自定义事件处理逻辑

在Program.cs中配置认证服务时,自定义OnRedirectToIdentityProvider和OnTokenValidated两个事件,实现state参数的注入和解析:

using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Web;

// 基础认证配置
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddInMemoryTokenCaches();

// 自定义OpenIdConnect参数处理逻辑
builder.Services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
    // 重定向到Azure AD前,向state注入自定义参数
    options.Events.OnRedirectToIdentityProvider = context =>
    {
        // 获取原始请求的子域名和用户要跳转的路径
        var originalHost = context.Request.Host.Value;
        var originalRequestPath = context.Request.Path + context.Request.QueryString;
        
        // 构造自定义state数据,必须保留默认生成的CSRF令牌用于后续校验
        var customState = new CustomStateData
        {
            Subdomain = originalHost.Split('.')[0],
            ReturnUrl = originalRequestPath,
            CsrfToken = context.Properties.Items["xsrf"]
        };
        
        // 序列化后做Base64编码,避免特殊字符被转义
        var stateJson = System.Text.Json.JsonSerializer.Serialize(customState);
        context.ProtocolMessage.State = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(stateJson));
        
        return Task.CompletedTask;
    };

    // Azure AD回调验证令牌后,解析state并设置最终跳转地址
    options.Events.OnTokenValidated = context =>
    {
        try
        {
            // 解码返回的state参数
            var stateBytes = Convert.FromBase64String(context.ProtocolMessage.State);
            var stateData = System.Text.Json.JsonSerializer.Deserialize<CustomStateData>(stateBytes);
            
            // 校验CSRF令牌,必须完成该步骤防止跨站请求伪造攻击
            if (stateData == null || stateData.CsrfToken != context.Properties.Items["xsrf"])
            {
                context.Fail("非法请求,CSRF校验不通过");
                return Task.CompletedTask;
            }

            // 构造对应子域名的跳转地址
            context.Properties.RedirectUri = $"https://{stateData.Subdomain}.myapp.com{stateData.ReturnUrl}";
        }
        catch
        {
            context.Fail("state参数解析失败");
        }
        
        return Task.CompletedTask;
    };
});

// 自定义state数据模型
public class CustomStateData
{
    public string Subdomain { get; set; }
    public string ReturnUrl { get; set; }
    public string CsrfToken { get; set; }
}

2. 注意事项

  • 必须保留框架默认生成的CSRF令牌并做校验,不要完全替换默认state值,符合RFC 6749第10.12节的安全要求
  • 自定义参数建议先序列化再做Base64编码,避免特殊字符被Azure AD截断或转义出错
  • 不要在state参数中存储敏感信息,也不要存储HTML内容,Azure AD会自动剥离HTML内容导致参数丢失
  • 共享重定向URI的域名需要和所有业务子域名属于同一个根域名,避免跨域安全限制

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 03:00:02