2014-10-08 22 views
8

Mi sono grattato la testa per 2 giorni. Sto usando WebAPI versione 2.2 e sto usando CORS. Questa configurazione funziona sul lato server, sono autorizzato ad ottenere il contenuto autorizzato dal codice del mio client web server ma non autorizzato nelle mie chiamate ajax.401 Non autorizzato quando si invia una richiesta Ajax a web API

Ecco la mia configurazione:

Web API Config

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); 

(Ho provato ogni combinazione di app.UseCors (CorsOptions.AllowAll) a ND config.EnableCors())

mio controller attributo:

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

Web Client

Ajax chiamata: Creazione

$.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 
      }); 

E, ultimo ma non meno importante, le mie intestazioni.

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 

Strumenti di sviluppo e affermazione di violinista non sono stati inviati cookie con la richiesta.

risposta

3

Credo che si stia mescolando tra l'autenticazione cookie e gettoni portatore qui, non sta inviando un token di accesso nell'intestazione di autorizzazione con la vostra richiesta, che è il motivo per cui continui a ricevere 401. Inoltre, devi solo consentire a CORS di utilizzare application.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); e rimuoverlo da dove l'attributo dei tuoi controller è presente anche dalla configurazione.

Controlla il mio Repo here dove ho implementato CORS e anche il front-end è AngularJS. funziona correttamente. Ecco anche lo live demo per questo repo, gli strumenti di sviluppo aperti e il monitoraggio delle richieste, dovresti vedere la richiesta di pre-volo prima di vedere la tua richiesta di ottenere HTTP.

Se è necessario solo per proteggere la vostra API utilizzando i token al portatore allora vi consiglio di leggere Token Based Authentication messaggio

+0

Ho lo stesso problema, ma non sto usando WebAPI come ospite di risorse, ma NancyFX. Tutto è reperibile se invocato da Curl o così, ma non da un'app AngularJS. L'endpoint del token va bene, ma se si tratta di un GET per un percorso fornito da Nancy, l'autenticazione ASP Net rifiuta un preflight OPTION con 401. Non ho idea di come superare questo problema. Inoltre non sono sicuro che il repository corrisponda alla demo: il repository utilizza client_id in richiesta token, ovviamente la demo no. Non correlato, ma un'indicazione, che entrambe le versioni sono diverse. – decades

0

Ciò potrebbe essere dovuto al fatto che l'API non è presente nell'URL come applicazione chiamante. L'URL per le API è: http://127.0.0.1/ (ignorando il percorso della cartella - che non importa)

..ma si sta chiamando da http://127.0.0.1:8888 che conta come un sito separato come il porto è diverso. Poiché il browser pensa che il sito sia diverso, non invierà il cookie.

Hai provato a provarlo da una pagina ospitata sullo stesso URL dell'API (con la stessa porta)?

Principalmente: controllare che sia possibile visualizzare il cookie inviato in Fiddler.

Si potrebbe anche trovare informazioni più pertinenti su come ottenere questo al lavoro on this answer

Problemi correlati