仅在 Angular 7 网络应用程序中为 "https://localhost:44361/connect/token" 获取错误 "blocked by CORS policy"
Getting an error "blocked by CORS policy" only for "https://localhost:44361/connect/token" in Angular 7 web app
完整错误如下图
Access to XMLHttpRequest at 'https://localhost:44361/connect/token' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
我在 .net core web api 的启动 class 中启用了核心策略,如下所示。
My ConfigureService method
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddDbContext<LEAFDDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), builder =>
{
builder.EnableRetryOnFailure(5, TimeSpan.FromSeconds(10), null);
}));
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<LEAFDDbContext>()
.AddDefaultTokenProviders();
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
Installer.ConfigureServices(services);
//services.AddCors();
//services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
//services.AddSingleton<IAuthenticationSchemeProvider, CustomAuthenticationSchemeProvider>();
//services.AddAuthentication(options =>
//{
// //options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
// //options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
// //options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
// options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
// options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
//})
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.Events.OnRedirectToLogin = ctx =>
{
// if it is an ajax/api request, don't redirect
// to login page.
if (!(IsAjaxRequest(ctx.Request) || IsApiRequest(ctx.Request)))
{
ctx.Response.Redirect(ctx.RedirectUri);
return Task.CompletedTask;
}
ctx.Response.StatusCode = StatusCodes.Status401Unauthorized;
return ctx.Response.WriteAsync("Unauthorized");
};
})
.AddOAuthValidation()
//services.AddAuthentication()
.AddOpenIdConnectServer(options =>
{
options.Provider = new AuthorizationProvider();
// Enable the authorization and token endpoints.
options.AuthorizationEndpointPath = "/connect/authorize";
options.TokenEndpointPath = "/connect/token";
options.AllowInsecureHttp = true;
// Note: to override the default access token format and use JWT, assign AccessTokenHandler:
//
options.AccessTokenHandler = new JwtSecurityTokenHandler
{
InboundClaimTypeMap = new Dictionary<string, string>(),
OutboundClaimTypeMap = new Dictionary<string, string>()
};
//
// Note: when using JWT as the access token format, you have to register a signing key.
//
// You can register a new ephemeral key, that is discarded when the application shuts down.
// Tokens signed using this key are automatically invalidated and thus this method
// should only be used during development:
//
options.SigningCredentials.AddEphemeralKey();
//
// On production, using a X.509 certificate stored in the machine store is recommended.
// You can generate a self-signed certificate using Pluralsight's self-cert utility:
// https://s3.amazonaws.com/pluralsight-free/keith-brown/samples/SelfCert.zip
//
//options.SigningCredentials.AddCertificate("7D2A741FE34CC2C7369237A5F2078988E17A6A75");
});
}
Configure method
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
//app.UseOAuthValidation();
app.UseAuthentication();
app.UseMvc();
app.UseMiddleware();
app.UseCors("CorsPolicy");
//app.UseCors(builder => builder.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin().AllowCredentials());
app.UseWelcomePage();
}
除了“https://localhost:44361/connect/token”之外的所有其他调用都按预期工作:获取令牌时。
我正在将来自 Angular 7 网络应用程序的所有请求发送到 .net 核心网络 api。
作为解决方法,我安装了来自 google chrome 的跨源资源共享扩展,我需要更改代码级别以永久解决此问题。
这是我想出的最终解决方案。
我没有直接从 Angular 7 应用程序调用“https://localhost:44361/connect/token”,而是在 API 控制器中创建了一个方法,该方法将调用上述调用并获取令牌。因此,每当我需要时,我只需要在 API 控制器中调用新创建的方法。
新api调用如下
[HttpPost]
[Route("/api/[controller]/Token")]
[EnableCors("CorsPolicy")]
public async Task<ContentResult> Token(LoginTokenRequestModel model)
{
string UserId = string.Empty;
try
{
using (HttpClient httpClient = new HttpClient())
{
if (!String.IsNullOrEmpty(model.Email))
{
var content = new FormUrlEncodedContent(new KeyValuePair<string, string>[]{
new KeyValuePair<string, string>("grant_type", model.grant_type),
new KeyValuePair<string, string>("client_secret", model.client_secret),
new KeyValuePair<string, string>("client_id", model.client_id),
new KeyValuePair<string, string>("username", model.Email),
new KeyValuePair<string, string>("password", model.Password),
});
string apiURL = "https://localhost:44361";
var response = await httpClient.PostAsync(apiURL + "/connect/token", content);
var resultContent = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var token = JsonConvert.DeserializeObject<object>(resultContent);
return new ContentResult
{
Content = token.ToString(),
ContentType = "text/plain",
StatusCode = 200
};
}
return new ContentResult
{
Content = JsonConvert.DeserializeObject<object>(resultContent).ToString(),
ContentType = "text/plain",
StatusCode = 200
};
}
}
}
catch (Exception ex)
{
return new ContentResult
{
Content = ex.Message,
ContentType = "text/plain",
StatusCode = 400
};
}
return new ContentResult
{
Content = "",
ContentType = "text/plain",
StatusCode = 400
};
}
这解决了我的问题。
在 app.useMvc()
之前使用app.UseCors()
。当涉及到中间件调用时,顺序很重要。就个人而言,我将其保存在确定 if-else
.
的环境中
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseCors("CorsDevPolicy");
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMiddleware(typeof(ErrorHandlingMiddleware));
app.UseMvc();
}
完整错误如下图
Access to XMLHttpRequest at 'https://localhost:44361/connect/token' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
我在 .net core web api 的启动 class 中启用了核心策略,如下所示。
My ConfigureService method
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddDbContext<LEAFDDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), builder =>
{
builder.EnableRetryOnFailure(5, TimeSpan.FromSeconds(10), null);
}));
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<LEAFDDbContext>()
.AddDefaultTokenProviders();
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
Installer.ConfigureServices(services);
//services.AddCors();
//services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
//services.AddSingleton<IAuthenticationSchemeProvider, CustomAuthenticationSchemeProvider>();
//services.AddAuthentication(options =>
//{
// //options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
// //options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
// //options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
// options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
// options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
//})
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.Events.OnRedirectToLogin = ctx =>
{
// if it is an ajax/api request, don't redirect
// to login page.
if (!(IsAjaxRequest(ctx.Request) || IsApiRequest(ctx.Request)))
{
ctx.Response.Redirect(ctx.RedirectUri);
return Task.CompletedTask;
}
ctx.Response.StatusCode = StatusCodes.Status401Unauthorized;
return ctx.Response.WriteAsync("Unauthorized");
};
})
.AddOAuthValidation()
//services.AddAuthentication()
.AddOpenIdConnectServer(options =>
{
options.Provider = new AuthorizationProvider();
// Enable the authorization and token endpoints.
options.AuthorizationEndpointPath = "/connect/authorize";
options.TokenEndpointPath = "/connect/token";
options.AllowInsecureHttp = true;
// Note: to override the default access token format and use JWT, assign AccessTokenHandler:
//
options.AccessTokenHandler = new JwtSecurityTokenHandler
{
InboundClaimTypeMap = new Dictionary<string, string>(),
OutboundClaimTypeMap = new Dictionary<string, string>()
};
//
// Note: when using JWT as the access token format, you have to register a signing key.
//
// You can register a new ephemeral key, that is discarded when the application shuts down.
// Tokens signed using this key are automatically invalidated and thus this method
// should only be used during development:
//
options.SigningCredentials.AddEphemeralKey();
//
// On production, using a X.509 certificate stored in the machine store is recommended.
// You can generate a self-signed certificate using Pluralsight's self-cert utility:
// https://s3.amazonaws.com/pluralsight-free/keith-brown/samples/SelfCert.zip
//
//options.SigningCredentials.AddCertificate("7D2A741FE34CC2C7369237A5F2078988E17A6A75");
});
}
Configure method
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
//app.UseOAuthValidation();
app.UseAuthentication();
app.UseMvc();
app.UseMiddleware();
app.UseCors("CorsPolicy");
//app.UseCors(builder => builder.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin().AllowCredentials());
app.UseWelcomePage();
}
除了“https://localhost:44361/connect/token”之外的所有其他调用都按预期工作:获取令牌时。
我正在将来自 Angular 7 网络应用程序的所有请求发送到 .net 核心网络 api。
作为解决方法,我安装了来自 google chrome 的跨源资源共享扩展,我需要更改代码级别以永久解决此问题。
这是我想出的最终解决方案。
我没有直接从 Angular 7 应用程序调用“https://localhost:44361/connect/token”,而是在 API 控制器中创建了一个方法,该方法将调用上述调用并获取令牌。因此,每当我需要时,我只需要在 API 控制器中调用新创建的方法。
新api调用如下
[HttpPost]
[Route("/api/[controller]/Token")]
[EnableCors("CorsPolicy")]
public async Task<ContentResult> Token(LoginTokenRequestModel model)
{
string UserId = string.Empty;
try
{
using (HttpClient httpClient = new HttpClient())
{
if (!String.IsNullOrEmpty(model.Email))
{
var content = new FormUrlEncodedContent(new KeyValuePair<string, string>[]{
new KeyValuePair<string, string>("grant_type", model.grant_type),
new KeyValuePair<string, string>("client_secret", model.client_secret),
new KeyValuePair<string, string>("client_id", model.client_id),
new KeyValuePair<string, string>("username", model.Email),
new KeyValuePair<string, string>("password", model.Password),
});
string apiURL = "https://localhost:44361";
var response = await httpClient.PostAsync(apiURL + "/connect/token", content);
var resultContent = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var token = JsonConvert.DeserializeObject<object>(resultContent);
return new ContentResult
{
Content = token.ToString(),
ContentType = "text/plain",
StatusCode = 200
};
}
return new ContentResult
{
Content = JsonConvert.DeserializeObject<object>(resultContent).ToString(),
ContentType = "text/plain",
StatusCode = 200
};
}
}
}
catch (Exception ex)
{
return new ContentResult
{
Content = ex.Message,
ContentType = "text/plain",
StatusCode = 400
};
}
return new ContentResult
{
Content = "",
ContentType = "text/plain",
StatusCode = 400
};
}
这解决了我的问题。
在 app.useMvc()
之前使用app.UseCors()
。当涉及到中间件调用时,顺序很重要。就个人而言,我将其保存在确定 if-else
.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseCors("CorsDevPolicy");
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMiddleware(typeof(ErrorHandlingMiddleware));
app.UseMvc();
}