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

ASP.Net Core 3.1部署PCF后SSO认证报错:oauth state缺失或无效

问题

在ASP.Net Core 3.1中实现SSO认证并部署到Pivot Cloud Foundry(PCF)后,出现未处理异常,本地运行正常。异常信息如下:

处理请求时发生未处理异常。
Exception: The oauth state was missing or invalid.
Unknown location
Exception: 处理远程登录时遇到错误。
Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler.HandleRequestAsync()

相关代码如下:

HomeController.cs

#if !LOCALTEST
        [Authorize]
#endif
        public IActionResult Index()
        {
            string user = "";
            if (User.Identity.IsAuthenticated)
            {
                user = User.Identity.Name;
            }
            else
            {

                // WindowsIdentity.GetCurrent
                user = WindowsIdentity.GetCurrent().Name.Substring(WindowsIdentity.GetCurrent().Name.LastIndexOf(@"\") + 1);
            }
            TempData["user"] = user;
            
            return View();
        }

Manifest.yml

---
applications:
- name: ApplicationName
  memory: 1G
  stack: cflinuxfs3
  buildpacks:
    - dicf_dotnet_core_buildpack_2339_cflinuxfs3
  instances: 2
  disk_quota: 1G
  
  env:
     ASPNETCORE_ENVIRONMENT: Development
     GRANT_TYPE: authorization_code
     SSO_IDENTITY_PROVIDERS : XXX-sso
     SSO_SCOPES : openid,roles,user_attributes
     SSO_AUTO_APPROVED_SCOPES : openid,roles,user_attributes
     SSO_USERINFO_URL : https://appsso.login.sr3.pcf.xxx.com/userinfo
     services : 
     - serviceName

Startup.cs

public void ConfigureServices(IServiceCollection services)
        {
          
            services.AddSession();
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddMvc();
            services.Configure<MyOptions>(myOptions =>
            {
                myOptions.ConnString = Configuration.GetConnectionString("DefaultConnection");
            });
            services
           .AddMvc()
           .AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
            services.AddScoped<IRepository, RepositoryConcrete>();
            services.AddControllersWithViews();
            services.AddRazorPages();

            services.AddCloudFoundryContainerIdentity(Configuration);

            services.AddAuthentication((options) =>
            {
                options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = CloudFoundryDefaults.AuthenticationScheme;
            })
            .AddCookie((options) =>
            {
                options.AccessDeniedPath = new PathString("/Home/AccessDenied");
            })
            .AddCloudFoundryOAuth(Configuration);

            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;

            });
            services.AddControllersWithViews();

            var serviceInfos = CloudFoundryServiceInfoCreator.Instance(Configuration);
           var ssoInfo = serviceInfos.GetServiceInfos<SsoServiceInfo>().FirstOrDefault()
                  ?? throw new NullReferenceException("Service info for an SSO Provider was not found!");

            userInfoEndPoint = ssoInfo.AuthDomain + "/userinfo";
        
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }
            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseForwardedHeaders(new ForwardedHeadersOptions
            {
                ForwardedHeaders = ForwardedHeaders.XForwardedProto
            });
            app.UseSession();
            app.UseAuthentication();
            app.UseAuthorization();

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

        }
排查与修复建议

1. 解决多实例Session不一致问题

部署了2个实例,默认内存型Session会导致跨实例请求时丢失OAuth State值(State存储在Session中):

  • 改用PCF提供的Redis服务作为分布式Session存储:
    // 在ConfigureServices中添加
    services.AddStackExchangeRedisCache(options =>
    {
        options.Configuration = Configuration.GetConnectionString("RedisConnection");
    });
    services.AddSession(options =>
    {
        options.IdleTimeout = TimeSpan.FromMinutes(30);
        options.Cookie.HttpOnly = true;
        options.Cookie.IsEssential = true;
    });
    
  • 确保已将Redis服务绑定到应用,连接字符串正确注入配置。

2. 调整Cookie策略配置

当前CheckConsentNeeded = true会阻止非必要Cookie,而OAuth认证依赖的Cookie属于必要范畴:

  • 修改CookiePolicyOptions:
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.CheckConsentNeeded = context => false;
        options.MinimumSameSitePolicy = SameSiteMode.None;
        options.Secure = CookieSecurePolicy.Always; // PCF强制HTTPS环境下启用
    });
    
  • 同步调整Cookie认证选项,确保多实例环境下Cookie可共享:
    .AddCookie((options) =>
    {
        options.AccessDeniedPath = new PathString("/Home/AccessDenied");
        options.Cookie.Name = ".AspNetCore.Cookies";
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
        options.Cookie.SameSite = SameSiteMode.None;
        options.Cookie.HttpOnly = true;
        options.Cookie.IsEssential = true;
    })
    

3. 修正ForwardedHeaders中间件顺序

当前UseForwardedHeaders在UseRouting之后,会导致认证中间件无法正确获取真实请求协议,影响Cookie的Secure属性:

  • 调整中间件顺序至UseRouting之前:
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    
    // 移至UseRouting之前
    app.UseForwardedHeaders(new ForwardedHeadersOptions
    {
        ForwardedHeaders = ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost
    });
    
    app.UseRouting();
    app.UseSession();
    app.UseAuthentication();
    app.UseAuthorization();
    

4. 修正环境配置

Manifest.yml中ASPNETCORE_ENVIRONMENT设为Development,生产环境需改为Production以启用安全配置:

env:
  ASPNETCORE_ENVIRONMENT: Production

5. 验证SSO服务绑定

确认serviceName对应的SSO服务已正确绑定,且服务实例的回调URL配置为应用的PCF域名(如https://applicationname.sr3.pcf.xxx.com/signin-cloudfoundry),回调URL不匹配会直接导致State验证失败。

6. 清理冗余代码

  • Startup.cs中重复调用了services.AddControllersWithViews(),保留一次即可;
  • PCF容器环境下不会执行WindowsIdentity.GetCurrent()逻辑,可保留但无需额外修改。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 06:24:25