由于 CORS 问题,无法访问 API
Posted
技术标签:
【中文标题】由于 CORS 问题,无法访问 API【英文标题】:Not able to access API due to CORS issue 【发布时间】:2021-11-09 21:10:00 【问题描述】:使用 Asp.Net Core 5 和 OpenIdDict for OpenId 我有 3 个应用程序:
Auth with OpenIdDict running on https://localhost:5000
API running on https://localhost:5001
SPA running on https://localhost:5002
从我的 Angular 的 SPA 我可以登录和注销。
我能够访问允许匿名访问的 API 端点。
如果我尝试在不发送访问令牌的情况下访问需要身份验证的 API 端点,我会收到预期的 401 错误。
问题
当我尝试访问需要身份验证的 API 端点并在授权标头中发送访问令牌时,我收到错误:
Access to XMLHttpRequest at 'https://localhost:5001/v1.0/posts' from origin 'https://localhost:5002' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
POST https://localhost:5001/v1.0/posts
更新
以防万一我的 Angular 请求是:
httpClient.post(`https://localhost:5001/v1.0/posts`,
title: "My post", body: "Some text" ,
headers:
'Content-Type': 'application/json',
'Authorization': `Bearer $user.access_token`
).subscribe();
API Startup 的ConfigureServices
和Configure
方法是:
public void ConfigureServices(IServiceCollection services)
services
.AddControllers()
.SetCompatibilityVersion(CompatibilityVersion.Latest)
.AddJsonOptions()
.AddFluentValidation();
services
.AddApiVersioning(x =>
x.ApiVersionSelector = new CurrentImplementationApiVersionSelector(x);
x.AssumeDefaultVersionWhenUnspecified = true;
x.DefaultApiVersion = new ApiVersion(1, 0);
x.ReportApiVersions = true;
x.RouteConstraintName = "version";
);
services.AddDbContext<Context>(x =>
x.UseSqlServer(Configuration.Get<Options>().Database.Connection, y =>
y.MigrationsHistoryTable("__Migrations");
y.UseNetTopologySuite();
).EnableSensitiveDataLogging(Environment.IsDevelopment())
.UseQueryTrackingBehavior(QueryTrackingBehavior.TrackAll));
services.AddRouting(x => x.AppendTrailingSlash = false; x.LowercaseUrls = true; );
services.AddCors(x =>
x.AddPolicy("Cors", y =>
y.WithOrigins("https://localhost:5000", "https://localhost:5002").AllowAnyMethod().AllowAnyHeader().AllowCredentials());
);
services.AddAuthentication(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);
services
.AddAuthorization(x =>
x.AddPolicy(Policy.Admin, y => y.RequireClaim("Admin"));
);
services
.AddIdentityCore<User>(x => x.AddDefaultOptions())
.AddEntityFrameworkStores<Context>()
.AddDefaultTokenProviders();
services.AddOpenIddict()
.AddValidation(x =>
x.SetIssuer("https://localhost:5000");
x.AddAudiences("api");
x.UseIntrospection();
x.SetClientId("api").SetClientSecret("test");
x.UseSystemNetHttp();
x.UseAspNetCore();
);
services.AddHsts();
services.AddHttpsRedirection();
services.AddMediatR(typeof(Startup));
services.Configure<ApiBehaviorOptions>(x =>
x.SuppressModelStateInvalidFilter = false;
x.SuppressInferBindingSourcesForParameters = true;
x.InvalidModelStateResponseFactory = context => new InvalidModelStateResponseFactory(context).GetResponse();
);
services.Configure<Options>(Configuration);
public void Configure(IApplicationBuilder application, IWebHostEnvironment environment)
application.UseHsts();
application.UseHttpsRedirection();
application.UseRouting();
application.UseCors("Cors");
application.UseAuthentication();
application.UseAuthorization();
application.UseEndpoints(x =>
x.MapControllers();
);
Auth Startup 的ConfigureServices
和Configure
方法是:
public void ConfigureServices(IServiceCollection services)
services
.AddControllersWithViews()
.SetCompatibilityVersion(CompatibilityVersion.Latest)
.AddJsonOptions()
.AddFluentValidation();
services.AddRouting(x => x.AppendTrailingSlash = false; x.LowercaseUrls = true; );
services.AddCors(x =>
x.AddPolicy("Cors", y =>
y.WithOrigins("https://localhost:5001", "https://localhost:5002").AllowAnyMethod().AllowAnyHeader().AllowCredentials());
);
services.AddDbContext<Context>(x =>
x.UseSqlServer(Configuration.Get<Options>().Database.Connection, y =>
y.MigrationsHistoryTable("__Migrations");
y.UseNetTopologySuite();
).EnableSensitiveDataLogging(Environment.IsDevelopment())
.UseQueryTrackingBehavior(QueryTrackingBehavior.TrackAll);
x.UseOpenIddict<Data.Entities.Application, Authorization, Scope, Token, Int32>();
);
services
.AddIdentityCoreWithAuthentication<User>(x => x.AddDefaultOptions())
.AddEntityFrameworkStores<Context>()
.AddDefaultTokenProviders()
.AddUserConfirmation<UserConfirmation<User>>();
services.ConfigureApplicationCookie(x =>
x.AccessDeniedPath = "/denied";
x.Cookie.HttpOnly = false;
x.Cookie.Name = "auth";
x.ExpireTimeSpan = TimeSpan.FromMinutes(40);
x.LoginPath = "/login";
x.LogoutPath = "/logout";
x.SlidingExpiration = true;
);
services.AddOpenIddict()
.AddCore(x =>
x.UseEntityFrameworkCore()
.UseDbContext<Context>()
.ReplaceDefaultEntities<Data.Entities.Application, Authorization, Scope, Token, Int32>();
)
.AddServer(x =>
x.SetAuthorizationEndpointUris("/connect/authorize")
.SetLogoutEndpointUris("/connect/logout")
.SetTokenEndpointUris("/connect/token")
.SetIntrospectionEndpointUris("/connect/introspect")
.SetUserinfoEndpointUris("/connect/userinfo");
x.RegisterClaims(OpenIddictConstants.Claims.Email, OpenIddictConstants.Claims.Name, OpenIddictConstants.Claims.Role);
x.RegisterScopes(OpenIddictConstants.Scopes.Profile, OpenIddictConstants.Scopes.Email, OpenIddictConstants.Scopes.Roles, OpenIddictConstants.Scopes.OfflineAccess);
x.AllowAuthorizationCodeFlow()
.AllowRefreshTokenFlow();
x.AddDevelopmentEncryptionCertificate().AddDevelopmentSigningCertificate();
x.UseAspNetCore()
.EnableAuthorizationEndpointPassthrough()
.EnableLogoutEndpointPassthrough()
.EnableTokenEndpointPassthrough()
.EnableUserinfoEndpointPassthrough()
.EnableStatusCodePagesIntegration();
)
.AddValidation(x =>
x.UseLocalServer();
x.UseAspNetCore();
);
services.AddHsts();
services.AddHttpsRedirection();
services.AddMediatR(typeof(Startup));
services.Configure<Options>(Configuration);
services.AddScoped<IUserClaimsPrincipalFactory<User>, UserClaimsPrincipalFactory>();
public void Configure(IApplicationBuilder application, IWebHostEnvironment environment)
application.UseHsts();
application.UseHttpsRedirection();
application.UseStaticFiles();
application.UseRouting();
application.UseCors("Cors");
application.UseAuthentication();
application.UseAuthorization();
application.UseEndpoints(x =>
x.MapDefaultControllerRoute();
);
我做错了什么?
我尝试了很多,但结果总是一样。
【问题讨论】:
【参考方案1】:你写的配置应该是正确的。
最初我也遇到了很多关于 CORS 的问题。最后我发现app.UseXXX
的顺序是必不可少的。要使用 CORS,请务必调用 UseCors
after UseRouting
和 before UseAuthentication
和 UseAuthorization
app.UseRouting(...);
app.UseCors(...);
app.UseAuthentication(...);
app.UseAuthorization(...);
【讨论】:
我在 API 和 AUTH 应用程序中都有这个顺序 确保调用API的应用代码调用的是https,而不是http url?即使您使用的 http-redirection 可能不起作用 是的,我的所有请求都使用了 HTTPS。这真的很奇怪,因为在我登录之前,我可以访问不需要身份验证的端点,例如https://localhost:5001/news
...登录后,如果我在没有 Authorization
标头的情况下调用该端点,我很好...如果我添加了 Authorisation
标头,但出现 CORS 错误。
您是否在 OpenIdDict 的客户端 Cors Orgins 中列出了您的应用程序 url?
@A.Hasemeyer 我不确定我是否理解您的问题。你的意思是,如果我在AddCors
方法中列出了我在https://localhost:5002
上运行的SPA 客户端应用程序?是的,我在里面有AllowAnyOrigin
。这是你的意思吗?以上是关于由于 CORS 问题,无法访问 API的主要内容,如果未能解决你的问题,请参考以下文章
Safari:重新加载后“由于访问控制检查而无法加载 Fetch API”
由于 Spring 5 中的 Access / CORS 问题,无法访问我的后端的 URL [重复]