2017-08-21 8 views
2

Ich versuche gerade, die Sicherheit mit Angular 4 (4.3.5) auf dem neu veröffentlichten Asp.Net Core 2.0 und speziell Anti-Fälschungs-Token richtig zu machen.ValidateAntiForgeryToken funktioniert mit Angular 4 und Asp.Net Core 2

Ich benutze JavascriptServices, die die Starter-Anwendung bietet (es ist die Standard-Angular-Vorlage in Visual Studio 2017.3). Javascript-Dienste hostet die Hauptseite der Angular-Site auf einer .cshtml-Seite. Dies erweist sich als ziemlich vorteilhaft, da ich dann alles unter Verwendung der Standardformularauthentifizierung (dot net core Identity) absperren kann, die den Benutzer auf eine separate (nicht eckige) Anmeldeseite um/Account/Login umleitet, wenn der Benutzer dies nicht tut eingeloggt. Sie können sich dann auf dieser Seite einloggen und auf die Homepage weitergeleitet werden, und der Whirlpool läuft im Kontext des berechtigten Benutzers.

Diese funktionierende Anwendung kann here gefunden werden.

Das letzte Teil des Puzzles ist das Erhalten der ValidateAntiForgeryToken Attribute. Dies ist in Ordnung, wenn Sie sich auf der Account/Login-Seite anmelden, da es nicht im Kontext von angular 4 läuft. Aber wenn ich innerhalb von Angular 4 auf der Startseite läuft, wenn ich einen Post zurück auf den Server mache, wird der Post wird von ValidateAntiForgeryToken blockiert, wenn dieses Attribut vorhanden ist.

Aus diesem Grund habe ich das ValidateAntiForgeryToken-Attribut in der Account/Logout-Methode auskommentiert. Dies liegt daran, dass ich mich von der Site mithilfe eines Angular-HTTP-Posts abmelde. Es funktioniert, wenn das Attribut nicht verwendet wird, aber es schlägt fehl/ist blockiert, wenn es verwendet wird.

Im Anschluss an die Angular 4-Dokumentation, gefunden here, habe ich den Anti-Fälschungs-Token-Namen geändert, um zu entsprechen, was Angular 4 erkennt. Um dies zu tun, modifizierte ich meine Startup.cs Datei, indem in einigen Zeilen wie folgt:

public void ConfigureServices(IServiceCollection services) 
{ 
      services.AddAntiforgery(options => 
      { 
       options.Cookie.Name = "XSRF-TOKEN"; 
       options.Cookie.HttpOnly = false; 
      }); 
... 
} 

Dies sollte die Angular App aktivieren, um die Anti Forgery Cookie Zugriff mit dem Namen Angular 4 erwartet.

Innerhalb meiner App habe ich gerade gewechselt, um den neuen HttpClient-Dienst zu verwenden (anscheinend wurde der HTTP-Dienst veraltet!), Der einen Interceptor verwenden soll, um das XSRF_TOKEN automatisch an den Server zu senden.

Aber ich konnte diese Arbeit nicht machen.

habe ich versucht, einen Standard-Anruf Post den Httpclient-Dienst:

this.httpClient.post(this.baseUrl + 'Account/Logout', "", options).subscribe(result => { 
    location.replace("/"); 
}, error => { 
    console.error(error); 
}) 

Ich versuchte Header manuell hinzufügen:

let token = this.cookieService.get("XSRF-TOKEN"); 
console.log(token); 

var httpHeaders = new HttpHeaders({ 'XSRF-TOKEN': token }) 

this.httpClient.post(this.baseUrl + 'Account/Logout', "", { headers: httpHeaders }).subscribe(result => { 
    location.replace("/"); 
}, error => { 
    console.error(error); 
}) 

Ich versuchte, den alten Service mit sowohl mit als auch ohne Zusatz-Header:

let token = this.cookieService.get("XSRF-TOKEN"); 
     console.log(token); 

     let headers = new Headers({ 
      //'Content-Type': 'application/json', 
      'X-XSRF-TOKEN': token 
     }); 
     let options = new RequestOptions({ headers: headers }); 
     this.http.post(this.baseUrl + 'Account/Logout', "", options).subscribe(result => { 
      location.replace("/") 
     }, error => console.error(error)); 

Leider hatte ich kein Glück. Hat es noch jemand geschafft, dass das funktioniert?

Antwort

0

Ok, ich habe eine Lösung gefunden.

Meine Index.cshtml Seite sieht nun wie folgt aus:

@Html.AntiForgeryToken() 

<app>Loading...</app> 

<script src="~/dist/vendor.js" asp-append-version="true"></script> 
@section scripts { 
    <script src="~/dist/main-client.js" asp-append-version="true"></script> 
} 

Was das bedeutet ist eine Anti-Fälschung Token auf der Serverseite zu erzeugen, und legen Sie sie in einem verborgenen Eingabefeld auf der Seite.Wenn Sie Seite Quelle ansehen, dann sieht, dass versteckte Eingabefeld wie folgt aus:

<input name="__RequestVerificationToken" type="hidden" value="CfDJ8DaEnvKVNL9EhPVzHKQWhC-PeT4eNm_svdTEyGZje4WnH34sBfG_D_AphtPzBM1JEkQUHsSX1KWBivxAOtPsOvfMKs5N_dLn0Sr3xRG-N2s0oFaa3-yvG87qdzXYm1yBSYH7dlRiBu5It3wi2iYzWqyo4B1i_iRtmikz41gmuldze8VE72zVqmeHZav5rQiHkw" /> 

In meinem Logout-Methode, erhalte ich das Token und es in den Header an den Server-Side-Controller vor. Der Name der Kopfzeile ist RequestVerificationToken, keine Unterstriche erforderlich.

Logout() { 

    let token: any = $("input[name=__RequestVerificationToken]").val(); 
    if (token !== null) { 
     var httpHeaders: any = new HttpHeaders({ 'RequestVerificationToken': token }); 

     this.httpClient.post("/Account/Logout", null, { headers: httpHeaders }).subscribe(() => { 
      window.location.replace("/Account/Login"); 
     }, error => { 
      console.log(error); 
     }); 
    } 
} 

Auf der Server-Seite, der Fälschungs Filter läuft, vergleicht es mit dem übermittelten Wert, und wenn es der Wert erwartet wird, wird das Server-Seite Account/Logout-Verfahren ausgeführt werden kann.

Die serverseitige Methode sieht wie folgt aus:

// 
// POST: /Account/Logout 
[HttpPost] 
[ValidateAntiForgeryToken] 
public async Task<IActionResult> Logout() 
{ 
    await _signInManager.SignOutAsync(); 
    return RedirectToAction(nameof(HomeController.Index), "Home"); 
} 

einen Haltepunkt in der Logout-Methode Einlochen wird beweisen, dass sie ausgeführt wird.

Vielleicht gibt es hier ein Problem. Ich bin mir nicht sicher, ob sich das Token bei jeder Anfrage ändert. Ich habe diesbezüglich noch keine Tests gemacht. Wenn dies der Fall ist, muss nach jeder Anfrage ein neues Token zur Seite hinzugefügt werden.

Außerdem musste ich das Verhalten des Standardcookies nicht ändern. Ich mache das nicht die Angular 4-Methode. Es ist nur der ASP.Net-Ansatz. Das heißt, in der ConfigureServices Methode in der Startup.cs Datei, ich habe die Cookie-Änderungen auf Kommentar:

public void ConfigureServices(IServiceCollection services) 
     { 
      //services.AddAntiforgery(options => 
      //{ 
      // options.Cookie.Name = "XSRF-TOKEN"; 
      // options.Cookie.HttpOnly = false; 
      //}); 

Wenn Sie glauben, einen besseren Weg, dies zu tun gefunden habe, mit allen Mitteln, bitte posten Sie Ihre Lösung.

1

Hatte das gleiche Problem. Meine Lösung:

  • eine Func auf die Anforderungspipeline, wie die (F #) Hinzufügen:

    member this.Configure(app: IApplicationBuilder, env: IHostingEnvironment, appLifetime : IApplicationLifetime, antiforgery : IAntiforgery) = 
    let tokenMiddleware = fun (context : HttpContext) (next: Func<Task>) -> 
              let path = context.Request.Path.Value 
              if path <> null && not (path.ToLower().Contains("/api")) then 
               let tokens = antiforgery.GetAndStoreTokens(context) 
               context.Response.Cookies.Append("XSRF-TOKEN", 
                tokens.RequestToken, CookieOptions (
                      HttpOnly = false, 
                      Secure = false 
                     ) 
              ) 
              next.Invoke() 
    app 
        .UseStaticFiles() 
        .UseIdentityServer() 
        .Use(tokenMiddleware) 
    

Der Punkt hier ist auf false sicher gesetzt, andernfalls wird der Code Skript nicht in der Lage sein, den Cookie zu holen.

  • In Angular hatte ich

    login(login: UserLogin, completed:() => void, failed: (message: string) => void) { 
    const token = this.cookieService.get('XSRF-TOKEN'); 
    const httpHeaders = (token) ? new HttpHeaders({ 'X-XSRF-TOKEN': token }) : null; 
    
    this.http.post(this.apiUrl() + AccountServiceService.Login_Url, login, { headers: httpHeaders }) 
    

für mich manuell die Header-Optionen einstellen ok Works. HIH

0

Dieses Problem bezieht sich auf HttpClient HttpXsrfInterceptor does not set xsrf token for absolute urls und HttpClient does not set X-XSRF-Token on Http Post.

Ich würde vorschlagen, wenn Sie in der Lage sind, mit einer relativen URL zu arbeiten, können Sie ohne this.baseUrl nach dem Versuch:

this.httpClient.post('Account/Logout', "", options).subscribe(result => { 
    location.replace("/"); 
}, error => { 
    console.error(error); 
}) 

Sie müssen auch die folgenden zu Ihrem Start hinzuzufügen.cs-Datei XSRF-TOKEN als Set-Cookie weitergeben müssen:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IAntiforgery antiforgery) 
    { 
... 
app.Use(next => context => 
     { 
      if (
       string.Equals(context.Request.Path.Value, "/", StringComparison.OrdinalIgnoreCase) || 
       string.Equals(context.Request.Path.Value, "/index.html", StringComparison.OrdinalIgnoreCase)) 
      { 
       // We can send the request token as a JavaScript-readable cookie, and Angular will use it by default. 
       var tokens = antiforgery.GetAndStoreTokens(context); 
       context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, 
        new CookieOptions() { HttpOnly = false }); 
      } 

      return next(context); 
     }); 
... 

Alternativ können Sie versuchen, Ihre eigenen XSRFInterceptor zu schreiben. Eine Probe wird gezeigt here.

Verwandte Themen