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的启动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'sConfigureServices
和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();
});
}
我做错了什么?
我已经尝试了很多,但总是相同的结果。
你写的配置应该是正确的。
最初我对CORS也有很多问题。最后我发现app.UseXXX
的顺序是至关重要的。要使用CORS,在之后调用UseCors
是很重要的前的UseRouting
和UseAuthentication
和UseAuthorization
app.UseRouting(...);
app.UseCors(...);
app.UseAuthentication(...);
app.UseAuthorization(...);