如何使用带有承载令牌的HttpClient访问[授权]控制器操作?获得401“观众无效”

问题描述 投票:1回答:1

应用程序中有四个客户端:

  1. angular.application - 资源所有者
  2. identity_ms.client - webapi app(.net core 2.1) 带有AspNetIdentity的IdentityServer4 AccountController具有注册用户,重置密码等的共享操作 具有安全操作的UserController。 UserController的Data操作具有[Authorize(Policy = "user.data")]属性
  3. ms_1.client - webapi app(.net core 2.1)
  4. request.client - 专门用于将来自ms_1.client的请求发送到identity_ms.client的UserController以获取一些用户数据。

我正在请求使用Postman的客户:

  1. qazxsw poi获取访问令牌
  2. http://localhost:identity_ms_port/connect/token从ms_1获取一些安全数据
  3. http://localhost:ms_1_port/api/secured/action从identity_ms获取一些安全的用户数据

一切都很好。

此外,ms_1服务有一个使用http://localhost:identity_ms_port/api/user/data请求http://localhost:identity_ms_port/api/user/data的安全操作。

System.Net.Http.HttpClient

我尝试过以下方法:

  1. 从请求到ms_1 Authorization标头检索access_token并使用它来访问用户/数据。
  2. 获取新的access_token以使用它访问用户/数据。请参阅代码块中的// identity_ms configuration public void ConfigureServices(IServiceCollection services) { services.AddCors(/*cors options*/); services .AddMvc() .AddApplicationPart(/*Assembly*/) .AddJsonOptions(/*SerializerSettings*/) .SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services.Configure<IISOptions>(iis => { iis.AuthenticationDisplayName = "Windows"; iis.AutomaticAuthentication = false; }); var clients = new List<Client> { new Client { ClientId = "angular.application", ClientSecrets = { new Secret("secret".Sha256()) }, AllowedScopes = { "user.data.scope", "ms_1.scope", "identity_ms.scope" }, AllowedGrantTypes = GrantTypes.ResourceOwnerPassword }, new Client { ClientId = "ms_1.client", ClientSecrets = { new Secret("secret".Sha256()) }, AllowedScopes = { "user.data.scope", "ms_1.scope" }, AllowedGrantTypes = GrantTypes.ClientCredentials }, new Client { ClientId = "identity_ms.client", ClientSecrets = { new Secret("secret".Sha256()) }, AllowedScopes = { "user.data.scope", IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile }, AllowedGrantTypes = GrantTypes.Implicit }, new Client { ClientId = "request.client", AllowedScopes = { "user.data.scope" }, AllowedGrantTypes = GrantTypes.ClientCredentials, ClientSecrets = { new Secret("secret".Sha256()) } } }; var apiResources = new List<ApiResource> { new ApiResource("ms_1.scope", "MS1 microservice scope"), new ApiResource("identity_ms.scope", "Identity microservice scope"), new ApiResource("user.data.scope", "Requests between microservices scope") }; var identityResources = new List<IdentityResource> { new IdentityResources.OpenId(), new IdentityResources.Profile() }; services .AddAuthorization(options => options.AddPolicy("user.data", policy => policy.RequireScope("user.data.scope"))) .AddIdentityServer() .AddDeveloperSigningCredential() .AddInMemoryIdentityResources(identityResources) .AddInMemoryApiResources(apiResources) .AddInMemoryClients(clients); services .AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.Audience = "identity_ms.scope"; options.RequireHttpsMetadata = false; options.Authority = "http://localhost:identity_ms_port"; }); services.AddSwaggerGen(/*swagger options*/); } public void Configure(IApplicationBuilder app) { app.UseMiddleware<CustomMiddleware>(); app.UseIdentityServer(); app.UseAuthentication(); app.UseCors("Policy"); app.UseHttpsRedirection(); app.UseMvc(/*routes*/); app.UseSwagger(); } // ms_1.client configuration public void ConfigureServices(IServiceCollection services) { services.AddCors(/*cors options*/); services .AddMvc() .AddJsonOptions(/*SerializerSettings*/) .SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services .AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => { options.Audience = "ms_1.scope"; options.RequireHttpsMetadata = false; options.Authority = "http://localhost:identity_ms_port"; }); } public void Configure(IApplicationBuilder app) { app.UseMiddleware<CustomMiddleware>(); app.UseAuthentication(); app.UseCors("Policy"); app.UseStaticFiles(); app.UseHttpsRedirection(); app.UseMvc(/*routes*/); app.UseSwagger(); } // ms_1.client action using HttpClient [HttpPost] public async Task<IActionResult> Post(ViewModel model) { //... using (var client = new TokenClient("http://localhost:identity_ms_port/connect/token", "ms_1.client", "secret")) { var response = await client.RequestClientCredentialsAsync("user.data.scope"); if (response.IsError) { throw new Exception($"{response.Error}{(string.IsNullOrEmpty(response.ErrorDescription) ? string.Empty : $": {response.ErrorDescription}")}", response.Exception); } if (string.IsNullOrWhiteSpace(response.AccessToken)) { throw new Exception("Access token is empty"); } var udClient = new HttpClient(); udClient.SetBearerToken(response.AccessToken); udClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); var result = await udClient.GetAsync("http://localhost:identity_ms_port/api/user/data"); } //... } 代码。

在这两种情况下,我都有正确的令牌,我可以使用它来从Postman请求安全/动作和用户/数据操作,但是HttpClient正在获得未经授权的响应(401)。

public async Task<IActionResult> Post(ViewModel model)

我究竟做错了什么?

identityserver4 dotnet-httpclient asp.net-core-2.1 bearer-token audience
1个回答
0
投票

在使用Response headers screenshot的客户端代码中,您没有请求API的任何范围,因此Identity Server 4发出的令牌不会包含API作为其中一个受众,然后您将从API获得401。

更改您的令牌请求以请求API范围。

HttpClient
© www.soinside.com 2019 - 2024. All rights reserved.