2014-10-08 123 views
8

我一直在为此挠了我的头2天。我正在使用WebAPI 2.2版,并且正在使用CORS。这个设置在服务器端工作,我被允许从我的Web客户端服务器代码获得授权内容,但在我的ajax调用中未经授权。401发送ajax请求到web api时未经授权

这里是我的配置:

的Web API配置

WebApiConfig:

public static class WebApiConfig 
{ 
    public static void Register(HttpConfiguration config) 
    { 

     // Web API configuration and services 
     // Configure Web API to use only bearer token authentication. 
     config.SuppressDefaultHostAuthentication(); 
     config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType)); 
     config.Filters.Add(new HostAuthenticationFilter(DefaultAuthenticationTypes.ApplicationCookie)); 

     //enable cors 
     config.EnableCors(); 

     // Web API routes 
     config.MapHttpAttributeRoutes(); 

     config.Routes.MapHttpRoute(
      name: "DefaultApi", 
      routeTemplate: "api/{controller}/{id}", 
      defaults: new { id = RouteParameter.Optional } 
     ); 

     config.Filters.Add(new ValidationActionFilter()); 
    } 
} 

Startup.Auth.cs:

// Configure the db context and user manager to use a single instance per request 
     app.CreatePerOwinContext(UserContext<ApplicationUser>.Create); 
     app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create); 

     // Enable the application to use a cookie to store information for the signed in user 
     // and to use a cookie to temporarily store information about a user logging in with a third party login provider 
     app.UseCookieAuthentication(new CookieAuthenticationOptions 
      { 
       AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, 
       CookieHttpOnly = true, 
       CookieName = "Outpour.Api.Auth" 
      } 
     ); 

     //app.UseCors(CorsOptions.AllowAll); 
     //app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); 

     // Configure the application for OAuth based flow 
     PublicClientId = "self"; 
     OAuthOptions = new OAuthAuthorizationServerOptions 
     { 
      TokenEndpointPath = new PathString("/Token"), 
      Provider = new ApplicationOAuthProvider(PublicClientId), 
      AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"), 
      AccessTokenExpireTimeSpan = TimeSpan.FromDays(14), 
      AllowInsecureHttp = true 
     }; 

     // Enable the application to use bearer tokens to authenticate users 
     app.UseOAuthBearerTokens(OAuthOptions); 

(我已经想尽app.UseCors的组合(CorsOptions.AllowAll)a第二config.EnableCors())

我的控制器属性:

[Authorize] 
[EnableCors("http://localhost:8080", "*", "*", SupportsCredentials = true)] 
[RoutePrefix("api/videos")] 
public class VideosController : ApiController... 

Web客户端

AJAX调用:

$.ajaxPrefilter(function (options, originalOptions, jqXHR) { 
      options.crossDomain = { 
       crossDomain: true 
      }; 
      options.xhrFields = { 
       withCredentials: true 
      }; 
     }); 

     function ajaxGetVideoResolutionList() { 
      var request = { 
       type: "GET", 
       dataType: "json", 
       timeout: Outpour.ajaxTimeOut, 
       url: Outpour.apiRoot + "/videos/resolutions" 
      }; 
      $.ajax(request).done(onAjaxSuccess).fail(onAjaxError); 

Cookie建立:

var result = await WebApiService.Instance.AuthenticateAsync<SignInResult>(model.Email, model.Password); 

      FormsAuthentication.SetAuthCookie(result.AccessToken, model.RememberMe); 

      var claims = new[] 
      { 
       new Claim(ClaimTypes.Name, result.UserName), //Name is the default name claim type, and UserName is the one known also in Web API. 
       new Claim(ClaimTypes.NameIdentifier, result.UserName) //If you want to use User.Identity.GetUserId in Web API, you need a NameIdentifier claim. 
      }; 

      var authTicket = new AuthenticationTicket(new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie), new AuthenticationProperties 
      { 
       ExpiresUtc = result.Expires, 
       IsPersistent = model.RememberMe, 
       IssuedUtc = result.Issued, 
       RedirectUri = redirectUrl 
      }); 

      byte[] userData = DataSerializers.Ticket.Serialize(authTicket); 

      byte[] protectedData = MachineKey.Protect(userData, new[] { "Microsoft.Owin.Security.Cookies.CookieAuthenticationMiddleware", DefaultAuthenticationTypes.ApplicationCookie, "v1" }); 

      string protectedText = TextEncodings.Base64Url.Encode(protectedData); 

      Response.Cookies.Add(new HttpCookie("Outpour.Api.Auth") 
      { 
       HttpOnly = true, 
       Expires = result.Expires.UtcDateTime, 
       Value = protectedText 
      }); 

最后但并非最不重要的是,我的标题。

Remote Address:127.0.0.1:8888 
Request URL:http://127.0.0.1/api/videos/resolutions 
Request Method:GET 
Status Code:401 Unauthorized 

**Request Headersview source** 
Accept:application/json, text/javascript, */*; q=0.01 
Accept-Encoding:gzip,deflate,sdch 
Accept-Language:en-US,en;q=0.8 
Cache-Control:no-cache 
Host:127.0.0.1 
Origin:http://localhost:8080 
Pragma:no-cache 
Proxy-Connection:keep-alive 
Referer:http://localhost:8080/video/upload 
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36 

**Response Headersview source** 
Access-Control-Allow-Credentials:true 
Access-Control-Allow-Origin:http://localhost:8080 
Cache-Control:no-cache 
Content-Length:61 
Content-Type:application/json; charset=utf-8 
Date:Wed, 08 Oct 2014 04:01:19 GMT 
Expires:-1 
Pragma:no-cache 
Server:Microsoft-IIS/8.0 
WWW-Authenticate:Bearer 
X-AspNet-Version:4.0.30319 
X-Powered-By:ASP.NET 

开发人员工具和提琴手声称没有与请求一起发送的cookie。

回答

3

我相信你的cookies验证和这里承载令牌之间的混合,你是不是发送符合您的要求Authorization头的访问令牌更多的相关信息,即这就是为什么你总是得到401. 以及您只需要允许使用application.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);的CORS,并从控制器属性中甚至从配置中删除它。

检查我的Repo here我已经实现了CORS,前端也是AngularJS。它工作正常。这个回购也是live demo,开放的开发者工具和监控请求,你应该看到pre-flight请求之前,你看到你的HTTP请求。

如果你只需要使用承载令牌,然后以保护您的API,我建议你阅读Token Based Authentication

+0

我有同样的问题,但我不使用的WebAPI作为资源的主机,但NancyFX。如果从curl或其他程序调用,所有东西都会找到,但不会从AngularJS应用程序中调用。令牌端点没有问题,但是如果涉及到Nancy提供的路由的GET,ASP网络认证会拒绝带有401的OPTION预检。我不知道如何解决这个问题。此外,我不确定回购是否与演示相匹配:回购在令牌请求中使用client_id,但演示显然不是。不相关,但一个迹象,两个版本是不同的。 – decades 2015-03-30 21:15:37

0

这可能是因为您的API不在作为调用应用程序的传入URL上。您的API的网址为: http://127.0.0.1/(忽略文件夹路径 - 无关紧要)

..但您从http://127.0.0.1:8888调用它作为单独站点,因为端口不同。由于浏览器认为该网站是不同的,它不会发送cookie。

您是否尝试过从与该API相同的URL(使用相同端口)托管的页面进行测试?

最重要的是:检查您是否可以看到通过Fiddler发送的Cookie。

你也可以找到让这个工作on this answer

相关问题