IdentityServer4 - 子聲明失去
我有一個 IdentityServer4 實例,我試圖在 nginx 代理後面的 Docker 容器中執行它。我基於 Git 儲存庫中的 AspNet 身份範例,但是在使用者成功註冊新帳戶後,我從 IdentityServer 收到“發生錯誤”並且日誌顯示
[07:46:39 ERR] An unhandled exception has occurred: sub claim is missing System.InvalidOperationException: sub claim is missing at IdentityServer4.IdentityServerPrincipal.AssertRequiredClaims(ClaimsPrincipal principal at IdentityServer4.Hosting.IdentityServerAuthenticationService.AugmentPrincipal(ClaimsPrincipal principal at IdentityServer4.Hosting.IdentityServerAuthenticationService.<SignInAsync>d__7.MoveNext我的 Startup.cs 看起來像這樣
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName(). var connectionString = Configuration.GetConnectionString("DefaultConnection"); var issuerUri = Configuration.GetSection("IssuerUri").Value; services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString)); services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); services.AddTransient<IEmailSender, EmailSender>(); services.AddMvc(); services.AddCors(o => o.AddPolicy("CorsPolicy", b => { b.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader(); })); services.AddIdentityServer(options => { options.IssuerUri = issuerUri; options.PublicOrigin = issuerUri; }) .AddDeveloperSigningCredential() // this adds the config data from DB (clients, resources) .AddConfigurationStore(options => { options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)); }) // this adds the operational data from DB (codes, tokens, consents) .AddOperationalStore(options => { options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)); // this enables automatic token cleanup. this is optional. //options.EnableTokenCleanup = true; //options.TokenCleanupInterval = 30; });我一定錯過了一些明顯的配置,但我看不到在哪裡。有任何想法嗎?
更新 我在這方面取得了一些進展,似乎已經克服了最初的錯誤。使用者現在已通過身份驗證,但 signin-oidc 頁面拋出錯誤
[11:33:21 INF] Request starting HTTP/1.1 POST http://mvcportal.co.uk/signin-oidc application/x-www-form-urlencoded 1565 [11:33:21 INF] AuthenticationScheme: Cookies signed in. [11:33:21 INF] Request finished in 684.8425ms 302 [11:33:27 INF] Request starting HTTP/1.1 POST http://mvcportal.co.uk/signin-oidc application/x-www-form-urlencoded 1565 [11:33:27 ERR] Message contains error: 'invalid_grant', error_description: 'error_description is null', error_uri: 'error_uri is null', status code '400'.我有一個有效的 JWT,但我注意到 idp 不等於頒發者。那是對的嗎?
{ "nbf": 1508758474, "exp": 1508758774, "iss": "http://myproxiedlogonsitebehindnginx.co.uk", "aud": "mvc.portal", "nonce": "636443552746808541.MGVjMzk2NTEtYmYwNS00NmQwLTllOTQtZDVjNjdlYTA2YWVlYTQ3Zjg1NjgtZDA1Yi00NDE0LWJiYmYtMjM4YzI1NjZlYTcx", "iat": 1508758474, "c_hash": "kG7wG8vSgRe5zdriHQ6iMA", "sid": "c9410ee8f27b69c32e43d5ac3d407f37", "sub": "e80fb854-cab2-4381-8057-19de0fea73f4", "auth_time": 1508757008, "idp": "local", "amr": [ "pwd" ] }更新 2 如果有幫助,這是 idsrv 上的客戶端配置
new Client { ClientId = "mvc.portal", ClientName = "Customer Portal", ClientUri = customerPortalBaseUri, ClientSecrets = { new Secret("21f51463-f436-4a84-92ce-1b520dd63a81".Sha256()) }, AllowedGrantTypes = GrantTypes.HybridAndClientCredentials, AllowAccessTokensViaBrowser = false, RedirectUris = { $"{customerPortalBaseUri}/signin-oidc"}, FrontChannelLogoutUri = $"{customerPortalBaseUri}/signout-oidc", PostLogoutRedirectUris = { $"{customerPortalBaseUri}/signout-callback-oidc" }, AllowOfflineAccess = true, RequireConsent = false, AllowedScopes = { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, IdentityServerConstants.StandardScopes.Email } }這是客戶端/門戶配置
services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = "oidc"; }) .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme) .AddOpenIdConnect("oidc", options => { options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.Authority = "http://myproxiedlogonsitebehindnginx.co.uk"; options.RequireHttpsMetadata = false; options.ClientId = "mvc.portal"; options.ClientSecret = "21f51463-f436-4a84-92ce-1b520dd63a81"; options.ResponseType = "code id_token"; options.SaveTokens = true; options.GetClaimsFromUserInfoEndpoint = true; });更新 3 所以現在我確信它與部署有關,因為如果我在本地機器上執行 mvc 應用程序但在容器中使用部署的 idsvr(在 nginx 後面),我可以毫無問題地進行身份驗證,但是如果我嘗試容器化門戶的版本,我仍然得到一個未處理的 500 沒有被記錄,然後如果我重試該操作,我會得到這個記錄:
[11:22:51 INF] Request starting HTTP/1.1 POST http://mvcportal.co.uk/signin-oidc application/x-www-form-urlencoded 1559 [11:22:51 ERR] Message contains error: 'invalid_grant', error_description: 'error_description is null', error_uri: 'error_uri is null', status code '400'. [11:22:51 ERR] Exception occurred while processing message. Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectProtocolException: Message contains error: 'invalid_grant'], error_description: 'error_description is null', error_uri: 'error_uri is null'.
所以我終於找到了它的底部。似乎 nginx 中的預設標頭限制效果不佳,我在日誌中發現了這一點
upstream sent too big header while reading response header from upstream更新 nginx 配置以包含這些行
proxy_buffer_size 128k; proxy_buffers 4 256k; proxy_busy_buffers_size 256k;防止了 502 錯誤,現在一切都很好。
我遇到了同樣的問題並通過添加解決了它:
.AddAspNetIdentity<ApplicationUser>();至
services.AddIdentityServer()在 Startup.cs