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

Asp.net Core微软OIDC库OnAuthorizationCodeReceived事件触发两次问题咨询

问题根因

经过排查,OnAuthorizationCodeReceived 事件触发两次的问题和当前的中间件顺序、异步代码写法、OIDC事件逻辑错误三个问题直接相关,均和反向代理环境特性有关:

  1. 中间件顺序错误:反向代理透传的 X-Forwarded-* 头需要提前解析才能让应用拿到正确的公网域名、协议信息,当前配置把 UseForwardedHeaders 放在了认证、会话中间件之后,导致回调校验时地址不匹配,第一次处理失败后框架自动触发重试,就会二次调用事件。
  2. 异步代码阻塞:OnAuthorizationCodeReceived 中混用 await 和 .Result 导致同步阻塞,反向代理超时后会自动重试请求,触发第二次事件。
  3. OIDC跳转逻辑错误:在 OnRedirectToIdentityProvider 中清空了所有协议参数,导致内置的 state、nonce、correlation 校验参数丢失,第一次回调校验失败后框架自动发起二次认证,触发二次回调。

修复方案

1. 调整中间件顺序

将 UseForwardedHeaders 放在所有中间件最前面,同时调整会话、认证的顺序符合ASP.NET Core规范:

// 必须放在最前面,优先解析反向代理透传的地址、协议头
app.UseForwardedHeaders();
app.UseHttpsRedirection();
app.UseStaticFiles();
//app.UseAntiXssMiddleware();
app.UseCookiePolicy();
app.UseRouting();
// 会话放在认证之前
app.UseSession();
app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
});

2. 修正OnAuthorizationCodeReceived异步写法

移除阻塞调用 .Result,改用纯异步写法,异常时主动终止后续默认处理逻辑:

OnAuthorizationCodeReceived = async authorizationCtx =>
{
    try
    {
        BellLogger.WriteLog("OnAuthorizationCodeReceived start:" + authorizationCtx.TokenEndpointRequest.Code, Framework.Common.LogType.Info);
        HttpClient httpClient = new HttpClient();
        TokenClientOptions tokenClientOptions = new TokenClientOptions()
        {
            ClientId = clientId,
            ClientSecret = clientSecret,
            Address = string.Format("{0}/v1/token", _authorityAPI)
        };
        var tokenClient = new TokenClient(httpClient, tokenClientOptions);
        // 移除.Result,用异步等待避免阻塞
        var tokenResponse = await tokenClient.RequestAuthorizationCodeTokenAsync(authorizationCtx.TokenEndpointRequest.Code, authorizationCtx.TokenEndpointRequest.RedirectUri);
        authorizationCtx.HandleCodeRedemption(tokenResponse.AccessToken, tokenResponse.IdentityToken);
    }
    catch (Exception ex)
    {
        Logger.WriteLog(ex, Framework.Common.LogType.Error);
        // 异常时终止后续默认处理,避免框架重试
        authorizationCtx.HandleResponse();
        authorizationCtx.Response.StatusCode = 500;
    }
}

3. 修复OIDC跳转逻辑

不要清空所有协议参数,避免内置校验参数丢失:

OnRedirectToIdentityProvider = (context) =>
{
    if (context.ProtocolMessage.RequestType == OpenIdConnectRequestType.Authentication)
    {
        // 注释清空参数的逻辑,保留state、nonce等内置校验参数
        // context.ProtocolMessage.Parameters.Clear();
        context.ProtocolMessage.IssuerAddress = centralLogin + "?RedirectURL=https://" + GetRequestHostName(context, Configuration);
        return Task.CompletedTask;
    }
    return Task.CompletedTask;
}

4. 补全CookiePolicy的SameSite处理逻辑

已定义的CheckSameSite方法没有注册到CookiePolicy中,补充注册避免部分浏览器Cookie拦截导致的重试:

services.Configure<CookiePolicyOptions>(options =>
{
    options.CheckConsentNeeded = context => true;
    options.MinimumSameSitePolicy = SameSiteMode.None;
    options.Secure = CookieSecurePolicy.Always;
    options.HandleSameSiteCookieCompatibility();
    // 注册自定义SameSite处理逻辑
    options.OnAppendCookie = cookieContext => 
        CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
    options.OnDeleteCookie = cookieContext => 
        CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 23:27:01