基于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
相关产品推荐
相关产品推荐

