2015-10-29 8 views
9
  1. voglio avere il progetto MVC su www.example1.com
  2. progetto WebAPI su api.example2.com

voglio limitare l'accesso alla WebAPI. Ho provato a implementare il token anti-contraffazione:Come posso implementare il token anti-contraffazione tra frontend MVC e Web Api su domini diversi?

Quando creo la richiesta GET su WebApi con token anti-contraffazione, ricevo un'eccezione perché la richiesta non contiene questo token.

Nel metodo chiamato ValidateRequestHeader è variabile cookie = null.

Come posso risolvere il codice seguente? È questa la soluzione corretta?

progetto MVC (front-end) - per lo sviluppo è localhost:33635:

Index.cshtml

<div class="container"> 


    <div class="row"> 

     <div class="col-md-12"> 


      <input id="get-request-button" type="button" class="btn btn-info" value="Create request to API Server" /> 

      <br /> 

      <div id="result"></div> 

     </div> 


    </div> 


</div> 


@section scripts 
{ 

    <script type="text/javascript"> 

     @functions{ 
      public string TokenHeaderValue() 
      { 
       string cookieToken, formToken; 
       AntiForgery.GetTokens(null, out cookieToken, out formToken); 
       return cookieToken + ":" + formToken; 
      } 
     } 

     $(function() { 

      $("#get-request-button").click(function() { 

       $.ajax("http://localhost:33887/api/values", { 
        type: "GET", 
        contentType: "application/json", 
        data: {}, 
        dataType: "json", 
        headers: { 
         'RequestVerificationToken': '@TokenHeaderValue()' 
        } 
       }).done(function (data) { 
        $("#result").html(data); 
       }); 

       return false; 
      }); 

     }); 


    </script> 

} 

progetto WebAPI - per lo sviluppo è localhost:33887:

WebApiConfig.cs

public static void Register(HttpConfiguration config) 
     { 
      // Web API configuration and services 

      config.EnableCors(new EnableCorsAttribute("http://localhost:33635", "*", "*")); 

      // Web API routes 
      config.MapHttpAttributeRoutes(); 

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

ValidateHttpAntiForgeryTokenAttribute.cs:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] 
    public sealed class ValidateHttpAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter 
    { 
     public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation) 
     { 
      var request = actionContext.Request; 

      try 
      { 
       if (IsAjaxRequest(request)) 
       { 
        ValidateRequestHeader(request); 
       } 
       else 
       { 
        AntiForgery.Validate(); 
       } 
      } 
      catch (Exception) 
      { 
       actionContext.Response = new HttpResponseMessage 
       { 
        StatusCode = HttpStatusCode.Forbidden, 
        RequestMessage = actionContext.ControllerContext.Request 
       }; 
       return FromResult(actionContext.Response); 
      } 
      return continuation(); 
     } 

     private Task<HttpResponseMessage> FromResult(HttpResponseMessage result) 
     { 
      var source = new TaskCompletionSource<HttpResponseMessage>(); 
      source.SetResult(result); 
      return source.Task; 
     } 

     private bool IsAjaxRequest(HttpRequestMessage request) 
     { 
      IEnumerable<string> xRequestedWithHeaders; 
      if (!request.Headers.TryGetValues("X-Requested-With", out xRequestedWithHeaders)) return false; 

      var headerValue = xRequestedWithHeaders.FirstOrDefault(); 

      return !String.IsNullOrEmpty(headerValue) && String.Equals(headerValue, "XMLHttpRequest", StringComparison.OrdinalIgnoreCase); 
     } 

     private void ValidateRequestHeader(HttpRequestMessage request) 
     { 
      var headers = request.Headers; 
      var cookie = headers 
        .GetCookies() 
        .Select(c => c[AntiForgeryConfig.CookieName]) 
        .FirstOrDefault(); 

      IEnumerable<string> xXsrfHeaders; 

      if (headers.TryGetValues("RequestVerificationToken", out xXsrfHeaders)) 
      { 
       var rvt = xXsrfHeaders.FirstOrDefault(); 

       if (cookie == null) 
       { 
        throw new InvalidOperationException($"Missing {AntiForgeryConfig.CookieName} cookie"); 
       } 

       AntiForgery.Validate(cookie.Value, rvt); 
      } 
      else 
      { 
       var headerBuilder = new StringBuilder(); 

       headerBuilder.AppendLine("Missing X-XSRF-Token HTTP header:"); 

       foreach (var header in headers) 
       { 
        headerBuilder.AppendFormat("- [{0}] = {1}", header.Key, header.Value); 
        headerBuilder.AppendLine(); 
       } 

       throw new InvalidOperationException(headerBuilder.ToString()); 
      } 
     } 
    } 

ValuesController:

public class ValuesController : ApiController 
    { 
     // GET: api/Values 
     [ValidateHttpAntiForgeryToken] 
     public IEnumerable<string> Get() 
     { 
      return new string[] { "value1", "value2" }; 
     } 

     // GET: api/Values/5 
     public string Get(int id) 
     { 
      return "value"; 
     } 

     // POST: api/Values 
     public void Post([FromBody]string value) 
     { 
     } 

     // PUT: api/Values/5 
     public void Put(int id, [FromBody]string value) 
     { 
     } 

     // DELETE: api/Values/5 
     public void Delete(int id) 
     { 
     } 
    } 
+0

@teovankot Voglio risolvere la condivisione di AntiForgeryToken tra due server. Il tuo link è stato risolto solo token anti-contraffazione su un server. – Jenan

+0

Spiacente, questo è il mio male –

risposta

6

Questo non è il modo per limitare l'accesso da un altro servizio. Il ForgeryToken aiuta a prevenire gli attacchi CSRF, ASP.NET MVC utilizza token anti-contraffazione, chiamati anche token di verifica delle richieste. Il client richiede una pagina HTML che contiene un modulo. Il server include due token nella risposta. Un token viene inviato come cookie. Quando si invia il modulo, quelli corrisponderanno sullo stesso server.

Credo, Quello che ti serve è il trust da example1.com a api.example2.com. An example sarebbe stackauth che è un dominio per servizi centralizzati nell'intero Stack Exchange network. Quindi puoi implementare l'autorizzazione di cui hai bisogno nel tuo progetto.

+0

Cosa intendi con "trust fron example1.com ed example2.com" - come posso fare questo? Grazie – Jenan

+0

Questa è la logica in cui si utilizza all'interno delle applicazioni Web. Ad esempio l'autenticazione e l'autorizzazione di un altro dominio con richieste specifiche inviate dall'applicazione corrente. –