我尝试了所有方法,但当我尝试从 React App 访问我的 api 时,我不断收到 401 错误。 我的 Api 是一个受身份服务器保护的 asp.net 核心。
从邮递员那里,我可以请求访问令牌并调用 api,它工作正常。 从浏览器中,我可以获得有效的访问令牌,但任何 api 调用都失败并显示 401。
在浏览器中失败的确切请求,在邮递员上工作正常(从开发工具复制为 cUrl,然后在邮递员中导入)。
我已经尝试了 http 和 https,我已经检查了启动时元素的顺序,我已经配置了 CORS……什么都没有。
我使用相同的 Web 应用作为 Identity Server 和 Api 服务器。
这是我的启动文件:
using FluentValidation.AspNetCore;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Pesabooks.Api.Common;
using Pesabooks.Application;
using Pesabooks.Application.Common.Interfaces;
using Pesabooks.Domain.Session;
using Pesabooks.Infrastructure;
using System.Threading.Tasks;
namespace Pesabooks.Api
{
public class Startup
{
public Startup(IConfiguration configuration, IWebHostEnvironment environment)
{
Configuration = configuration;
Environment = environment;
}
public IConfiguration Configuration { get; }
public IWebHostEnvironment Environment { get; }
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
builder =>
{
builder.WithOrigins("http://localhost:3000").AllowAnyMethod().AllowAnyHeader();
});
});
services.AddControllersWithViews()
.AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<IPesabooksDbContext>()); ;
services.AddApplication();
services.AddInfrastructure(Configuration, Environment);
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie("Cookies", options =>
{
options.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax;
});
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "http://localhost:5000";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
};
//options.Audience = "pesabooks";
options.RequireHttpsMetadata = false;
});
services.ConfigureApplicationCookie(options =>
{
options.Events.OnRedirectToLogin = context =>
{
context.Response.Headers["Location"] = context.RedirectUri;
context.Response.StatusCode = 401;
return Task.CompletedTask;
};
});
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Pesabooks.Api", Version = "v1" });
c.OperationFilter<AddRequiredHeaderParameter>();
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseCookiePolicy(new CookiePolicyOptions { MinimumSameSitePolicy = Microsoft.AspNetCore.Http.SameSiteMode.Strict });
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Pesabooks.Api v1"));
}
app.UseCustomExceptionHandler();
// app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthentication();
app.UseAuthorization();
app.UseIdentityServer();
app.UseTenantMiddleware();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "areas",
pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}"
);
endpoints.MapControllers();
});
}
}
}
这是我的身份服务器客户端设置:
{
"IdentityServer": {
"Clients": [
{
"ClientId": "Pesabooks.WebApp",
"ClientName": "Pesabooks Web App",
"AllowedGrantTypes": [ "implicit" ],
"AllowedScopes": [ "openid", "profile", "api" ],
"RequireClientSecret": false,
"RedirectUris": [ "http://localhost:3000/signin-oidc" ],
"PostLogoutRedirectUris": [ "http://localhost:3000/signout-oidc" ],
"AllowedCorsOrigins": [ "http://localhost:3000" ],
"AllowAccessTokensViaBrowser": true,
"Enabled": true
},
{
"ClientName": "Pesabooks.IntegrationTests",
"ClientId": "Pesabooks.IntegrationTests",
"AllowedGrantTypes": [ "password" ],
"AllowedScopes": [ "openid", "profile" ],
"ClientSecrets": [ { "Value": "*****" } ],
"Enabled": true
},
{
"ClientName": "Postman",
"ClientId": "postman",
"RequirePkce": false,
"AllowedGrantTypes": [ "authorization_code" ],
"AllowOfflineAccess": true,
"IdentityTokenLifetime": 86400,
"AccessTokenLifetime": 86400,
"RedirectUris": [ "https://www.getpostman.com/oauth2/callback" ],
"PostLogoutRedirectUris": [ "https://www.getpostman.com" ],
"AllowedCorsOrigins": [ "https://www.getpostman.com" ],
"AllowedScopes": [ "openid", "profile", "email", "api" ],
"ClientSecrets": [ { "Value": "*****" } ],
"AllowAccessTokensViaBrowser": true,
"RequireConsent": false,
"EnableLocalLogin": true,
"Enabled": true
}
]
}
}
这是在浏览器中失败但在邮递员中有效的请求示例:
curl 'http://localhost:5000/Account/Login?ReturnUrl=%2Fapi%2FAccounts%3FOnlySavings%3Dfalse%26IncludeDeactivated%3Dfalse' \
-H 'Connection: keep-alive' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjdBQjI4QUQzNEQ3OUMwOTNCMkY2NjZEQUU5MTYwQzczIiwidHlwIjoiYXQrand0In0.eyJuYmYiOjE2MTE1MDA4NDgsImV4cCI6MTYxMTUwNDQ0OCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAwIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAwL3Jlc291cmNlcyIsImNsaWVudF9pZCI6IlBlc2Fib29rcy5XZWJBcHAiLCJzdWIiOiIxIiwiYXV0aF90aW1lIjoxNjExNTAwODE4LCJpZHAiOiJsb2NhbCIsImp0aSI6IkYzRkE5MUIxRUM0MzIyNkRBNEZCNDU1QjQ2MTE1MzI5Iiwic2lkIjoiQTE3RDVDQjY3QTIxMDc0MjE4QzgyNTE1RjI5QjdGQUYiLCJpYXQiOjE2MTE1MDA4NDgsInNjb3BlIjpbIm9wZW5pZCIsInByb2ZpbGUiLCJhcGkiXSwiYW1yIjpbInB3ZCJdfQ.gGmUUmZNZLjhyY47diPXQHGXO0k1B8mss8FIdQuecFmp-SxRFls6nF7fU3bqQdQcadpIrZEjDGG2wth8IZIqg82K5L4jr9Nt8Rp8JMdvC-zn7TbHKV670QSYF6NIq5AKWNMi86oNfk9QYEIjM7p5DWjzSjH5LAmINQjwCNG0QhXccSqbUkmVxxsYQkCOfZnlsshrswP41ocNs1s_363v070Tc6ayrxBSYiqM5AbLs_5y4iSXgP1TzWdwxcavBng-vEA0lp5hU0ZNggmBid_GOrgKRfHNzv8518RfHtpa1VwptdkRMiba18t-HNezMw7WMh432Q6RxRvJGW6iq7S8eg' \
-H 'psbk-tenant: 5' \
-H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36' \
-H 'Sec-GPC: 1' \
-H 'Origin: http://localhost:3000' \
-H 'Sec-Fetch-Site: same-site' \
-H 'Sec-Fetch-Mode: cors' `
-H 'Sec-Fetch-Dest: empty' \
-H 'Referer: http://localhost:3000/' \
-H 'Accept-Language: en-US,en;q=0.9' \
--compressed
这是我在日志中得到的:
[11:28:48 Debug] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: Identity.Application was not authenticated.
[11:28:48 Debug] IdentityServer4.Hosting.CorsPolicyProvider
CORS request made for path: /.well-known/openid-configuration from origin: http://localhost:3000
[11:28:48 Debug] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: Identity.Application was not authenticated.
[11:28:48 Debug] IdentityServer4.Services.InMemoryCorsPolicyService
Client list checked and origin: http://localhost:3000 is allowed
[11:28:48 Information] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: Identity.Application was challenged.
[11:28:48 Debug] IdentityServer4.Hosting.CorsPolicyProvider
CorsPolicyService allowed origin: http://localhost:3000
[11:28:48 Debug] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: Identity.Application was not authenticated.
[11:28:48 Debug] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: Identity.Application was not authenticated.
[11:28:48 Debug] IdentityServer4.Hosting.EndpointRouter
Request path /.well-known/openid-configuration matched to endpoint type Discovery
[11:28:48 Debug] IdentityServer4.Hosting.EndpointRouter
Endpoint enabled: Discovery, successfully created handler: IdentityServer4.Endpoints.DiscoveryEndpoint
[11:28:48 Information] IdentityServer4.Hosting.IdentityServerMiddleware
Invoking IdentityServer endpoint: IdentityServer4.Endpoints.DiscoveryEndpoint for /.well-known/openid-configuration
[11:28:48 Debug] IdentityServer4.Endpoints.DiscoveryEndpoint
Start discovery request
[11:28:48 Debug] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: Identity.Application was successfully authenticated.
[11:28:48 Debug] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: Identity.Application was successfully authenticated.
[11:28:48 Debug] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: Identity.Application was successfully authenticated.
[11:28:48 Debug] IdentityServer4.Hosting.EndpointRouter
Request path /connect/checksession matched to endpoint type Checksession
[11:28:48 Debug] IdentityServer4.Hosting.EndpointRouter
Endpoint enabled: Checksession, successfully created handler: IdentityServer4.Endpoints.CheckSessionEndpoint
[11:28:48 Information] IdentityServer4.Hosting.IdentityServerMiddleware
Invoking IdentityServer endpoint: IdentityServer4.Endpoints.CheckSessionEndpoint for /connect/checksession
[11:28:48 Debug] IdentityServer4.Endpoints.CheckSessionEndpoint
Rendering check session result
提前致谢。
答案 0 :(得分:0)
为了帮助您调试,您应该配置您的日志并显示它们的调试输出。在 IdentityServer 解决方案中,您通常在 program.cs 类中控制它,如下面的示例来自 here:
只需将日志级别设置为 Debug 即可查看更多操作见解。
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Information)
.MinimumLevel.Override("System", LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft.AspNetCore.Authentication", LogEventLevel.Information)
.Enrich.FromLogContext()
// uncomment to write to Azure diagnostics stream
//.WriteTo.File(
// @"D:\home\LogFiles\Application\identityserver.txt",
// fileSizeLimitBytes: 1_000_000,
// rollOnFileSizeLimit: true,
// shared: true,
// flushToDiskInterval: TimeSpan.FromSeconds(1))
.WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}", theme: AnsiConsoleTheme.Code)
.CreateLogger();
答案 1 :(得分:0)
我做了一个测试并创建了一个单独的 web api 项目,它立即生效。
为身份服务器和我的 api 使用相同的服务器是一个坏主意,并且由于某些原因不起作用。
解决方案:为身份服务器使用专用的 Web 应用