【发布时间】:2019-03-19 09:37:04
【问题描述】:
我正在努力在我们拥有现有系统的情况下构建一些新功能。我们的目标是让不同的 Angular SPA 与 API 进行通信,从而为我们的旧版应用程序提供一个新界面。一个团队已设置 IdentityServer4 以使用旧应用程序进行凭据验证。
使用 Angular 7 编写的 SPA 使用隐式流程进行身份验证。 响应类型是“token id_token”我已经能够让这个流程工作,因为我可以让未经身份验证的用户来到站点,被踢到 IdentityServer 身份验证屏幕,登录正确的凭据,然后重定向回应用程序。当我取回令牌时,声明对象具有 aud 的单个值,即 SPA 的 client_id,例如 spa-client。 access_token 和 id_token 都是以 RS256 作为签名方式的 JWT。最后,我在 SPA 中创建了一个拦截器来发送 JWT(实际上它只是使用作为 access_token 发回的任何值)作为 API 请求的“Bearer”令牌。
我现在创建了一个 .NET Core 2.2 WebApi 应用程序来构建一个服务 API 以供 SPA 使用。此应用程序使用 IdentityServer4.AccessTokenValidation 包来“保护”API 我已经阅读了 IdentityServer4 文档中的部分。在我的 ConfigureServices 方法中,我编写了以下内容来配置身份验证: p>
services
.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
if (string.IsNullOrWhiteSpace(serviceConfiguration.Authentication.Authority)) throw new ConfigurationException("", nameof(serviceConfiguration.Authentication.Authority), "An authority must be defined.");
if (string.IsNullOrWhiteSpace(serviceConfiguration.Authentication.ApiName)) throw new ConfigurationException("", nameof(serviceConfiguration.Authentication.ApiName), "An api name must be defined.");
options.Authority = serviceConfiguration.Authentication.Authority;
options.ApiName = serviceConfiguration.Authentication.ApiName;
if (!string.IsNullOrWhiteSpace(serviceConfiguration.Authentication.ApiSecret))
{
options.ApiSecret = serviceConfiguration.Authentication.ApiSecret;
}
options.RequireHttpsMetadata = false;
options.SupportedTokens = SupportedTokens.Both;
}
serviceConfiguration 是我的 JSON appsettings.json 的强类型表示
我的理解是options.SupportedTokens = SupportedTokens.Both会检查JWT并进行自省。
现在所有这些都已设置好,我采用了由 API 模板创建的简单示例 ValuesController,并为其添加了 [Authorize] 属性。正如我所料,在 Postman 中对该端点执行一个简单的 GET 请求会返回 401。
接下来我尝试登录 SPA 并转到一个测试页面,该页面将执行相同的操作,但拦截器将拥有不记名令牌、access_token 或基本上是 JWT。我仍然从服务中收到 401。
查看服务输出的日志,我没有看到任何有用的具体内容:
信息:Microsoft.AspNetCore.Hosting.Internal.WebHost[1] 请求开始 HTTP/1.1 选项http://localhost:5001/api/values 信息: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] 请求开始 HTTP/1.1 选项http://localhost:5001/api/values 信息: Microsoft.AspNetCore.Cors.Infrastructure.CorsService[4] CORS 策略执行成功。信息:Microsoft.AspNetCore.Cors.Infrastructure.CorsService[4] CORS 策略执行成功。信息:Microsoft.AspNetCore.Hosting.Internal.WebHost[2] 请求在 61.1352 毫秒内完成 204 信息:Microsoft.AspNetCore.Hosting.Internal.WebHost[2] 请求在 61.1272 毫秒内完成 204 信息:Microsoft.AspNetCore.Hosting.Internal.WebHost[1] 请求开始 HTTP/1.1 GET http://localhost:5001/api/values application/json 信息: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] 请求开始 HTTP/1.1 GET http://localhost:5001/api/values application/json 信息: Microsoft.AspNetCore.Cors.Infrastructure.CorsService[4] CORS 策略执行成功。信息:Microsoft.AspNetCore.Cors.Infrastructure.CorsService[4] CORS 策略执行成功。信息:Microsoft.AspNetCore.Routing.EndpointMiddleware[0] 执行端点'Examples.TestApp.API.Web.Controllers.ValuesController.Get (Examples.TestApp.API.Web)'信息: Microsoft.AspNetCore.Routing.EndpointMiddleware[0] 执行端点'Examples.TestApp.API.Web.Controllers.ValuesController.Get (Examples.TestApp.API.Web)'信息: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] 与 {action = "Get", controller = "Values"} 匹配的路由。执行动作 示例.TestApp.API.Web.Controllers.ValuesController.Get (Examples.TestApp.API.Web)信息: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] 与 {action = "Get", controller = "Values"} 匹配的路由。执行动作 示例.TestApp.API.Web.Controllers.ValuesController.Get (Examples.TestApp.API.Web)信息: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2] 授权失败。信息:Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2] 授权失败。信息:Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3] 过滤器“Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter”处的请求授权失败。信息: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3] 过滤器“Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter”处的请求授权失败。信息: Microsoft.AspNetCore.Mvc.ChallengeResult[1] 使用身份验证方案 () 执行 ChallengeResult。信息:Microsoft.AspNetCore.Mvc.ChallengeResult[1] 使用身份验证方案 () 执行 ChallengeResult。信息:IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler[12] AuthenticationScheme:承载被挑战。信息:IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler[12] AuthenticationScheme:承载被挑战。信息:Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] 执行的动作 Examples.TestApp.API.Web.Controllers.ValuesController.Get (Examples.TestApp.API.Web) 在 166.3038ms 信息: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] 执行的动作 Examples.TestApp.API.Web.Controllers.ValuesController.Get (Examples.TestApp.API.Web) 在 162.8827ms 信息: Microsoft.AspNetCore.Routing.EndpointMiddleware[1] 执行端点'Examples.TestApp.API.Web.Controllers.ValuesController.Get (Examples.TestApp.API.Web)'信息: Microsoft.AspNetCore.Routing.EndpointMiddleware[1] 执行端点'Examples.TestApp.API.Web.Controllers.ValuesController.Get (Examples.TestApp.API.Web)'信息: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] 请求在 459.6677 毫秒内完成 401 信息:Microsoft.AspNetCore.Hosting.Internal.WebHost[2] 请求在 473.7648 毫秒内完成 401
将日志记录设置为 Trace 并没有透露任何其他信息。
我确实尝试过去 Postman 看看我是否可以手动对令牌进行自省。我将授权设置为基本并将用户名设置为“test-api”、api id 以及我在其客户端密码中设置的密码。在正文中,将其设置为 x-www-form-urlencoded,键为“token”,值为 access_token。我得到了 200 OK 的声明以及“活动:真实”。看起来应该不错吧?
我不拥有 IdentityServer 实现,所以除了能够登录到管理 UI 之外,我不太确定最后发生了什么。我已登录身份服务器的管理 UI,并仔细检查了客户端和 API 的设置。客户端被授予“api”范围,API 获得相同的范围“api”。这显示在自省响应中发回的范围以及我从客户端获得的令牌中。
我也尝试过设置options.SupportedTokens = SupportedTokens.Reference 和options.SupportedTokens = SupportedTokens.JWT。两者都没有任何变化。 :(
我做错了什么?这是配置问题还是我是个白痴(可能是后者)。
编辑:RE access_token 和 id_token
我在原始问题中不正确。标记不同(我需要查看的不仅仅是标题部分)。
观众很奇怪。解码时我从未注意这里可能存在的差异。我的感知力一定很烂!
访问令牌有 aud: "http:///resources" id_token 有 aud: "spa-client"
【问题讨论】:
标签: c# authentication asp.net-core identityserver4 openid-connect