【发布时间】:2019-12-12 17:43:38
【问题描述】:
我有两个正在解决的项目。一种是使用 asp.net 身份生成 JWT 令牌进行身份管理。在第二个项目中,有一些 API 是安全的,并且可以验证身份项目生成的令牌,但令牌验证不起作用。
在邮递员中调用 api store route 时出现此错误。我在授权标头中传递令牌。
处理请求时发生未处理的异常。 HttpRequestException:响应状态码不表示成功: 404(未找到)。 System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
IOException: IDX20804: Unable to retrieve document from: '[PII is 隐]'。 Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(字符串 地址,CancellationToken 取消)
InvalidOperationException:IDX20803:无法获取配置 来自:'[PII 被隐藏]'。 Microsoft.IdentityModel.Protocols.ConfigurationManager.GetConfigurationAsync(CancellationToken 取消)
堆栈查询 Cookie 标头 HttpRequestException:响应状态代码 不表示成功:404(未找到)。 System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode() Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(字符串 地址,CancellationToken 取消)
显示原始异常详细信息 System.Net.Http.HttpRequestException: 响应状态码不表示成功:404(未找到)。在 System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode() 在 Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(字符串 地址,CancellationToken 取消)IOException:IDX20804:无法 从以下位置检索文档:“[PII 已隐藏]”。 Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(字符串 地址,CancellationToken 取消) Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.GetAsync(字符串 地址,IDocumentRetriever 检索器,CancellationToken 取消) Microsoft.IdentityModel.Protocols.ConfigurationManager.GetConfigurationAsync(CancellationToken 取消)
显示原始异常详细信息 System.IO.IOException: IDX20804: Unable to 从以下位置检索文档:“[PII 已隐藏]”。 ---> System.Net.Http.HttpRequestException:响应状态代码不 表示成功:404(未找到)。在 System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode() 在 Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(字符串 address, CancellationToken cancel) --- 内部异常堆栈结束 跟踪---在 Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(字符串 地址,CancellationToken 取消)在 Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.GetAsync(字符串 地址,IDocumentRetriever 检索器,CancellationToken 取消)在 Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken 取消)InvalidOperationException:IDX20803:无法获取 配置来自:'[PII 被隐藏]'。 Microsoft.IdentityModel.Protocols.ConfigurationManager.GetConfigurationAsync(CancellationToken 取消) Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync() Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync() Microsoft.AspNetCore.Authentication.AuthenticationHandler.AuthenticateAsync() Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext 上下文,字符串方案) Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext 语境) Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext 上下文)
显示原始异常详细信息 System.InvalidOperationException: IDX20803: 无法从以下位置获取配置:“[PII 已隐藏]”。 ---> System.IO.IOException:IDX20804:无法从以下位置检索文档: '[PII 被隐藏]'。 ---> System.Net.Http.HttpRequestException:响应 状态码不表示成功:404(未找到)。在 System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode() 在 Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(字符串 address, CancellationToken cancel) --- 内部异常堆栈结束 跟踪---在 Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(字符串 地址,CancellationToken 取消)在 Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.GetAsync(字符串 地址,IDocumentRetriever 检索器,CancellationToken 取消)在 Microsoft.IdentityModel.Protocols.ConfigurationManager
1.GetConfigurationAsync(CancellationToken cancel) --- End of inner exception stack trace --- at Microsoft.IdentityModel.Protocols.ConfigurationManager1.GetConfigurationAsync(CancellationToken 取消)在 Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync() 在 Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync() 在 Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync() 在 Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext 上下文,字符串方案)在 Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext 上下文)在 Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext 上下文)
这是我在 Identity 项目中的 Startup.cs 类。
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Cosmonaut;
using Cosmonaut.Extensions.Microsoft.DependencyInjection;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using Triverse.Identity.Models;
using Triverse.Identity.Services;
using IdentityRole = Microsoft.AspNetCore.Identity.DocumentDB.IdentityRole;
namespace Triverse.Identity
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
var endPointUri = Configuration.GetValue<string>("AppSettings:EndpointUri");
var primaryKey = Configuration.GetValue<string>("AppSettings:PrimaryKey");
var databaseId = Configuration.GetValue<string>("AppSettings:DatabaseId");
var collectionId = Configuration.GetValue<string>("AppSettings:CollectionId");
var client = new DocumentClient(new Uri(endPointUri), primaryKey);
services.AddSingleton<IDocumentClient>(client);
// make sure the database exists!
var db = client.CreateDatabaseQuery().Where(d => d.Id == databaseId).AsEnumerable().FirstOrDefault()
?? client.CreateDatabaseAsync(new Database { Id = databaseId }).Result;
var databaseLink = db.SelfLink;
services.AddIdentityWithDocumentDBStores<ApplicationUser, IdentityRole>(
dbOptions =>
{
dbOptions.DocumentUrl = endPointUri;
dbOptions.DocumentKey = primaryKey;
dbOptions.DatabaseId = databaseId;
dbOptions.CollectionId = collectionId;
},
identityOptions =>
{
identityOptions.User.RequireUniqueEmail = true;
});
var cosmosSettings = new CosmosStoreSettings(databaseId, endPointUri, primaryKey);
services.AddCosmosStore<ApplicationUser>(cosmosSettings);
services.AddScoped<IAccountRepository, AccountRepository>();
services.AddTransient<ITokenService, TokenService>();
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(cfg =>
{
cfg.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = Configuration["Tokens:Issuer"],
ValidAudience = Configuration["Tokens:Audience"],
IssuerSigningKey =
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Tokens:Key"])),
ValidateLifetime = true
};
cfg.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
{
context.Response.Headers.Add("Token-Expired", "true");
context.Response.Headers.Add("access-control-expose-headers", "Token-Expired");
}
return Task.CompletedTask;
}
};
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAuthentication();
app.UseMvc();
}
}
}
这是我在 Identity 项目中的 appsettings.json。
"Tokens": {
"Key": "4343@!#ewewq",
"Issuer": "http://localhost:44376/",
"Audience": "http://localhost:44385/",
"ExpiryMinutes": "55",
"ValidateLifetime": true
}
这是我在 Store 项目中的 Startup.cs 类。
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Cosmonaut;
using Cosmonaut.Extensions.Microsoft.DependencyInjection;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using Store.API.Services;
namespace Store.API
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
var endPointUri = Configuration.GetValue<string>("AppSettings:EndpointUri");
var primaryKey = Configuration.GetValue<string>("AppSettings:PrimaryKey");
var databaseId = Configuration.GetValue<string>("AppSettings:DatabaseId");
var client = new DocumentClient(new Uri(endPointUri), primaryKey);
services.AddSingleton<IDocumentClient>(client);
var db = client.CreateDatabaseQuery().Where(d => d.Id == databaseId).AsEnumerable().FirstOrDefault()
?? client.CreateDatabaseAsync(new Database {Id = databaseId}).Result;
var databaseLink = db.SelfLink;
var cosmosSettings = new CosmosStoreSettings(databaseId, endPointUri, primaryKey);
services.AddCosmosStore<Models.Store>(cosmosSettings);
services.AddScoped<IStoreRepository, StoreRepository>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Authority = "http://localhost:44376/";
options.RequireHttpsMetadata = false;
options.Audience = "http://localhost:44385/";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAuthentication();
app.UseMvc();
}
}
}
这是我在 Store 项目中的控制器方法。
[HttpGet]
[Authorize]
public async Task<IActionResult> GetStores()
{
var stores = new
{
Id = 1,
Name = "T-Shirt",
Price = "120.00"
};
return Ok(stores);
}
这是我从 Identity 项目生成的 JWT 令牌。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzaGFAZG9tYWluLmNvbSIsImp0aSI6IjFjYjNkNjA2LWI4MGQtNGNlZC1hMWFjLThlYmUzNzc1ZGViOSIsIlVuaXF1ZUlkIjoiZjU1ZTM2MWQtYjFkYy00MDg4LTlmYjQtMDg3ZTI4OTFjNWI1IiwidW5pcXVlX25hbWUiOiJzaGFAZG9tYWluLmNvbSIsImZpcnN0TmFtZSI6IlNoYXduIiwibmJmIjoxNTY0OTkwMjA1LCJleHAiOjE1NjQ5OTM1MDUsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6NDQzNzYvIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo0NDM4NS8ifQ.ZBK8Fi14QUc9ObZx7ojg7LPcl8Qs2vrQyhZi7Dbk4Gg
【问题讨论】:
-
您的“Store”API 正在尝试内部调用
http://localhost:44376/.well-known/openid-configuration,但调用失败。您可以使用此IdentityModelEventSource.ShowPII = true;启用PII日志 - 将其添加到您的启动中(将其删除以用于生产)。 -
我该如何解决这个问题?我正在使用 asp.net 身份。
-
您是在本地托管吗?首先启用 PII,然后您必须验证该 URL 至少可以在本地访问。
-
我已启用 IdentityModelEventSource.ShowPII = true;这在启动课上。 URL 仍然无法访问。我没有使用身份服务器,我使用的是 asp.net 身份。
-
那么我的代码到底有什么问题?
标签: c# asp.net-core .net-core asp.net-identity jwt-auth