为啥 CORS 错误“对预检请求的响应未通过访问控制检查”?
Posted
技术标签:
【中文标题】为啥 CORS 错误“对预检请求的响应未通过访问控制检查”?【英文标题】:Why CORS error "Response to preflight request doesn't pass access control check"?为什么 CORS 错误“对预检请求的响应未通过访问控制检查”? 【发布时间】:2019-03-31 17:32:46 【问题描述】:我在我的项目中使用 具有 OAuth 授权的 ASP.NET Web API。
我尝试使用最佳实践将解决方案中的每一层解耦。 我有一个包含 AngularJS 文件和其他资源的 web 项目,这些文件和其他资源上传到 www.example.com,我还有另一个项目,它是受保护的后端 web api 控制器和服务器端的东西,上传到 api.example.com
在 localhost 中一切正常。当我将此发布到生产服务器时,对“/token”的请求成功,但在后端 api 中的任何控制器中请求任何操作都会返回此错误: “从源 'http://www.example.com' 访问 XMLHttpRequest 在 'http://api.example.com/someRoute' 已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:没有 'Access-Control-Allow-Origin' 标头存在于请求的资源上。”。
我在互联网上搜索了几乎所有活动链接以查找类似错误,但我还没有答案!
我从后端 API 中粘贴了一些代码,以便您更好地理解我的方法。
public partial class Startup
public void Configuration(IAppBuilder app)
HttpConfiguration httpConfig = new HttpConfiguration();
UnityConfig.Register(httpConfig);
ConfigureAuth(app);
WebApiConfig.Register(httpConfig);
app.UseWebApi(httpConfig);
#region AutoMapper Init
DtoMapping.Map();
#endregion
public void ConfigureAuth(IAppBuilder app)
// Configure the auth context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(AuthContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
//remove this line on production
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
Provider = new SimpleAuthorizationServerProvider()
;
// Token Generation
app.UseOAuthBearerTokens(OAuthServerOptions);
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
public class WebApiConfig
public static void Register(HttpConfiguration config)
EnableCorsAttribute cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
config.MapHttpAttributeRoutes();
//...
[EnableCors("*", "*", "*")]
public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
context.Validated();
return Task.FromResult<object>(null);
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] "*" );
IList<string> roleNames;
using (var _repo = new IdentityRepository())
var user = await _repo.FindUserAsync(context.UserName, context.Password);
if (user == null)
context.SetError("invalid_grant", "username or password is invalid.");
context.Rejected();
return;
roleNames = await _repo.GetRolesForUserAsync(user.Id);
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
foreach (var roleName in roleNames)
identity.AddClaim(new Claim(ClaimTypes.Role, roleName));
var props = new AuthenticationProperties(new Dictionary<string, string>
"userName", context.UserName
);
var ticket = new AuthenticationTicket(identity, props);
context.Validated(ticket);
那么,谁能帮帮我?
感谢您的宝贵时间。
【问题讨论】:
我认为它对您不起作用,因为您在 WebApiConfig 中全局设置了“Cors”,并在SimpleAuthorizationServerProvider
中附加了属性。尝试删除SimpleAuthorizationServerProvider
中的属性,然后重试。据我所知,我遇到了同样的问题,这对我有用。
另外,我建议只为 DEBUG (/Development) 设置 CORS,而不是为发布设置。这是一种不应始终禁用的安全机制。使用子域,您应该至少为子域设置 cors 而不是通配符。
感谢您的回答,但删除属性并不能解决问题。我认为“/token”用于生成访问令牌的唯一原因是授权提供程序类上可用的此属性。如果我删除它,对“/token”的 POST 请求会返回与请求任何其他路由相同的 cors 错误,因此登录过程将不起作用。我什至尝试将此属性放在 web api 控制器上,看看它是否有效,尽管使用了全局 cors 设置,但结果仍然相同。
出于您提到的安全原因,我肯定会删除星号并将 cors 限制在生产中的某些域中,但现在我只需要看看它是否适用于任何设置。
【参考方案1】:
如果有人想知道,这就是我解决这个问题的方法:
这不是关于不在 asp.net web api 中设置 cors 策略(正如我已经提到的那样,我做了Microsoft docs website 的建议。)
问题在于 IIS 未配置为处理 OPTION 动词方法! 并且因为飞行前请求使用了 OPTION 方法,所以总是找不到 404(来自网络服务器的拒绝),因此出现错误。
我应该提一下,直到今天我仍然不知道为什么“/token”在配置 Web 服务器之前起作用,为什么控制器没有相同的反应!
但无论如何,问题就这样解决了。 希望对您有所帮助!
【讨论】:
【参考方案2】:可能有点旧,但值得一提的是,您需要在 global.asax 中添加 cors 标头
protected void Application_BeginRequest(object sender, EventArgs e)
var context = System.Web.HttpContext.Current;
var origins = System.Configuration.ConfigurationManager.AppSettings["AllowedCorsDomain"]?.TrimEnd('/');
context.Response.AddHeader("Access-Control-Allow-Origin", origins);
if (context.Request.HttpMethod == "OPTIONS")
//These headers are handling the "pre-flight" OPTIONS call sent by the browser
context.Response.AddHeader("Access-Control-Allow-credentials", "true");
context.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, POST, DELETE, OPTIONS");
context.Response.AddHeader("Access-Control-Allow-Headers", "x-requested-with, Content-Type, origin, authorization, Accepts, accept, client-security-token, access-control-allow-headers");
context.Response.AddHeader("Access-Control-Max-Age", "86400");
context.Response.End();
【讨论】:
谢谢。 CORS 一直很繁琐。因为我只需要它用于 DEV,所以我将它包装在 #if DEBUG 中并继续我的工作。我必须对 Windows 身份验证进行的一项更改是将 Access-Control-Allow-credentials 移到条件之外。以上是关于为啥 CORS 错误“对预检请求的响应未通过访问控制检查”?的主要内容,如果未能解决你的问题,请参考以下文章
为啥只有 Angular 才会出现 CORS 错误? [复制]