Identity Server 4对接.NET 4.6.2 Web API受保护端点重定向问题
问题描述
我尝试将Identity Server 4用于基于.NET Framework 4.6.2开发的Web API,参照公开技术社区的相关回答说明使用了IdentityServer3.Contrib.AccessTokenValidation库,但调用受保护端点时会返回402重定向。
对比验证结果:同一个access token用于调用受Identity Server 4保护的.NET Core API时不会触发重定向,仅在.NET Framework 4.6.2环境下出现该问题。
API 侧配置代码
private void ConfigureAuth(IAppBuilder app) { app.Map("/api", apiApp => { apiApp.UseCors(corsOptions); apiApp.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions { Authority = apiAuthority, ValidationMode = ValidationMode.ValidationEndpoint, RequiredScopes = new[] { "api" } }); SetupOpenIdAuthentication(apiApp); }); } private static void SetupOpenIdAuthentication(IAppBuilder app) { app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = "Cookies", ExpireTimeSpan = new TimeSpan(0, Configuration.SessionTimeoutInMinutes, 0), SlidingExpiration = true }); app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions { Authority = apiAuthority, ClientId = "clientId", RedirectUri = apiRootUri + "Help", PostLogoutRedirectUri = apiRootUri, ResponseType = "id_token token", Scope = "openid profile roles api all_claims", SignInAsAuthenticationType = "Cookies", Notifications = new OpenIdConnectAuthenticationNotifications() { RedirectToIdentityProvider = n => { // 登出请求中补充id_token_hint参数 if (n.ProtocolMessage.RequestType == Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectRequestType.Logout) { var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token"); if (idTokenHint != null) { n.ProtocolMessage.IdTokenHint = idTokenHint.Value; } } if (n.ProtocolMessage.RequestType == Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectRequestType.Authentication) { // 拦截AJAX请求的401响应,不触发默认重定向 if (IsAjaxRequest(n.Request) && n.Response.StatusCode == (int)System.Net.HttpStatusCode.Unauthorized) { n.Response.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized; n.HandleResponse(); return Task.FromResult(0); } } return Task.FromResult(0); }, SecurityTokenValidated = n => { // 留存id_token用于登出流程 n.AuthenticationTicket.Identity.AddClaim( new Claim("id_token", n.ProtocolMessage.IdToken)); // 将Role声明转换为微软标准声明类型,确保未携带Bearer Token时API的Authorize特性可正常生效 foreach (var claim in n.AuthenticationTicket.Identity.Claims.Where(x => x.Type == JwtClaimTypes.Role).ToList()) { n.AuthenticationTicket.Identity.AddClaim(new Claim(ClaimTypes.Role, claim.Value)); } return Task.FromResult(0); }, AuthenticationFailed = n => { // 认证失败时重定向到错误页面 n.OwinContext.Response.Redirect("/Help/Error"); // TODO: 开发专属认证失败提示页 n.HandleResponse(); // 屏蔽默认异常抛出逻辑 return Task.FromResult(0); } } }); }
Identity Server 侧配置代码
var builder = services.AddIdentityServer(options => { options.Events.RaiseErrorEvents = true; options.Events.RaiseInformationEvents = true; options.Events.RaiseFailureEvents = true; options.Events.RaiseSuccessEvents = true; // 开启静态audience声明输出 options.EmitStaticAudienceClaim = true; }) .AddSigningCredential(rsaCertificate) .AddInMemoryIdentityResources(IdentityConfig.IdentityResources) .AddInMemoryApiScopes(IdentityConfig.ApiScopes) .AddInMemoryClients(IdentityConfig.Clients) .AddAspNetIdentity<User>() .AddProfileService<CustomProfileService>() .AddWsFederationPlugin(options => { options.Licensee = "License"; options.LicenseKey = "Key" }) .AddInMemoryRelyingParties(new List<RelyingParty>()); services.AddAuthentication(sharedOptions => { sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme; }) .AddWsFederation(options => { options.Wtrealm = "azureAppId"; options.MetadataAddress = "metadataAddress"; }); builder.Services.ConfigureApplicationCookie(options => { options.Cookie.IsEssential = true; options.Cookie.SameSite = SameSiteMode.None; // .NET Core 3.1环境下对应SameSiteMode.Unspecified });
Identity Server 中注册的API客户端配置
new Client { ClientId = "clientId", AllowedGrantTypes = GrantTypes.ImplicitAndClientCredentials, ClientSecrets = { new Secret("secret".Sha256()) }, RedirectUris = { "https://localhost:44302/", $"{apiUrl}/Help" }, PostLogoutRedirectUris = { $"{apiUrl}" }, AllowedScopes = new List<string> { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, "api", "roles", "all_claims" }, RequirePkce = false, AllowOfflineAccess = true, AllowAccessTokensViaBrowser = true }
补充说明
如需进一步排查问题可提供更多配置代码。
内容的提问来源于stack exchange,提问作者Nimish David Mathew
相关产品推荐
相关产品推荐

