ASP.NET WebApi 对 ValidateClientAuthentication 上的 OPTIONS 的 400 错误请求,即使在 context.Validated() 上也是如此

Posted

技术标签:

【中文标题】ASP.NET WebApi 对 ValidateClientAuthentication 上的 OPTIONS 的 400 错误请求,即使在 context.Validated() 上也是如此【英文标题】:ASP.NET WebApi Answer 400 Bad Request to OPTIONS on ValidateClientAuthentication, even on context.Validated() 【发布时间】:2016-03-28 21:59:59 【问题描述】:

我有一个 WebApi 项目的 angularjs html 客户端。当我通过 POSTMAN 或其他 REST Client 测试 API 时,似乎一切正常。

当我开始使用带有 angularjs 客户端的浏览器时,浏览器总是使用 OPTIONS 启动预检请求。在那里,我的 WebAPI 总是回答 400 Bad Request - 我仍处于“/api/token”阶段。

我已经将我的 WebAPI 项目的每一个点都附加到了调试器上。我还根据 SO 中关于如何启用 CORS 的几个答案更改了几点。其中一些我已经尝试过:更改 web.config 以在每个请求上添加启用 cors 的标头,将 cors 添加到 WebApi 启动,在“/token”覆盖的函数中启用 cors。

这是我得到的:

Angularjs TypeScript 调用“/api/token”:

logIn = (userName: string, userPassword: string): ng.IPromise<void> => 
    var postData = 
        "grant_type": "password",
        "client_id": this.appConfiguration.ClientId,
        "client_secret": this.appConfiguration.ClientSecret,
        "username": userName,
        "password": userPassword
    ;
    return this.$http.post<models.LoggedUserModel>('http://local.web.api/api/token', $.param(postData), 
        headers: 
            'Accept': 'application/json',
            'Content-Type': 'application/x-www-form-urlencoded'
        
    ).then((result) => 
        this.localStorageService.set('Auth', result);
        this.goHome(true);
    ).catch((error) => 
        console.warn(error);
    );

这是在我的 WebApi 上调用的唯一函数:

  public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
  
      // handle cors requests
      if (!string.IsNullOrEmpty(context.OwinContext.Request.Headers.Get("Origin")))
      
          context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new string[]  "*" );
      
      try
      
          // retrieve clientId and clientSecret from request body
          string clientId;
          string clientSecret;
          if (context.TryGetFormCredentials(out clientId, out clientSecret))
          
              // here it comes our application specific security code....
          
          else
          
              // this is part of enabling CORS..
              if (context.Request.Method.ToUpper() == "OPTIONS")
              
                  // it returns OK to preflight requests having an empty body
                  context.Validated();
              
          
      
      finally
      
          // log stuff...
      
  

如果我只是离开 OWIN Cors 的东西,添加标题并调用“context.Validated()”,一切都会继续。这是我得到的:

Firefox Network Tab:
--------------------
Request URL: http://local.web.api/api/token
Request method: OPTIONS
Remote address: 127.0.0.1:80
Status code: 400 Bad Request
Version: HTTP/1.1

Request headers:
----------------
Host: local.web.api
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.7,pt-BR;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization
Origin: http://local.web.client
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache

Response headers:
-----------------
Access-Control-Allow-Origin: *
Cache-Control: no-cache
Content-Length: 34
Content-Type: application/json;charset=UTF-8
Date: Tue, 22 Dec 2015 15:24:23 GMT
Expires: -1
Pragma: no-cache
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET

我真的很感激一些关于从哪里得到的想法。 这对我来说是全新的,我确实操作过其他一些 WebApi 项目 + angularjs。

【问题讨论】:

Access-Control-Request-Method: POST, OPTIONS 不允许并返回错误,您需要在配置中包含OPTIONS 并且OPTIONS 调用必须返回200 OK 内容不是必需的。恕我直言,CORS 信息的最佳来源enable-cors.org 我关注了enable-cors.org/server_aspnet.html 上的所有广告以启用 CORS,但我仍然收到 400 错误请求。我应该在哪里添加OPTIONS?什么配置?由于我的 WebApi 项目到达的唯一点是ValidateClientAuthentication,除了调用context.Validated() 之外,我还应该返回另一件事吗?感谢您的链接! 也许这个链接会有帮助:***.com/questions/17713412/… 【参考方案1】:

好的,这很糟糕,但我发现了问题所在。 我在 angularjs 上使用 http 拦截器,它会自动检查登录用户,并在需要时添加带有 Bearer 令牌的 Authorization 标头。问题是我做错了。

我在 config 对象中创建了一个新属性,bypassToken 作为布尔值,这将是添加或不添加 Authorization 标头的标志。删除它实际上修复了代码。不知道为什么,但是现在分析请求我可以看到所有标头实际上都按预期发送:Content-Type 在第一个案例中没有正确填写。很奇怪,虽然 angularjs 没有发出警告。

// http auth interceptor
angularApplication.factory('httpAuthInterceptor', ['$rootScope', '$injector', '$location', ($rootScope, $injector, $location): ng.IHttpInterceptor => 

    var $q: ng.IQService = $injector.get('$q');
    var localStorageService: ng.local.storage.ILocalStorageService = $injector.get('localStorageService');

    return 
        request: (config: ng.IRequestConfig): ng.IRequestConfig => 
            // check if headers are present
            config.headers = config.headers || ;

            // the error was here! I was trying to add properties to config that I think angular was not expecting
            // removing this line solved the issue
            // if (!config.bypassToken) 

            // check if user is logged in
            var loggedUserInfo = localStorageService.get<models.LoggedUserInfoModel>('Auth');
            if (loggedUserInfo) 
                config.headers['Authorization'] = 'Bearer ' + loggedUserInfo.access_token;
            
            return config;
        ,
        responseError: (rejection)  => 
            // check if user is logged in
            var loggedUserInfo = localStorageService.get<models.LoggedUserInfoModel>('Auth');
            if ((rejection.status === 401) && (loggedUserInfo)) 

                // if so, then the user must login againd
                localStorageService.remove('Auth');
                $location.path('/home');
                console.error(rejection);
            
            return $q.reject(rejection);
        
    ;
]);

感谢您的帮助。 我只是在这里发布这个,以防有人遇到类似的问题。 不要乱用config 对象!

【讨论】:

以上是关于ASP.NET WebApi 对 ValidateClientAuthentication 上的 OPTIONS 的 400 错误请求,即使在 context.Validated() 上也是如此的主要内容,如果未能解决你的问题,请参考以下文章

如何对 ASP.NET WebApi 的每个请求应用自定义验证到 JWT 令牌?

SPA (Aurelia) + ASP.NET Core WebAPI + Google 身份验证

对“asp.net core WebApi”的 ajax 调用返回一个奇怪/奇怪的值

ASP.NET WebApi 对 ValidateClientAuthentication 上的 OPTIONS 的 400 错误请求,即使在 context.Validated() 上也是如此

ASP .NET WebAPI 路由数据架构

使用asp.net webapi实现oData inlinecount [重复]