Asp.net-Identity

IdentityServer4 - 子聲明失去

  • September 12, 2020

我有一個 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

引用自:https://stackoverflow.com/questions/46884549