Play框架如何传递CSRF Token?Angular前端未在头/Cookie中发现该Token
Hey there! Let's work through this CSRF token issue with your Play + Angular setup. I've dealt with this exact scenario before, so here's a breakdown of what's going on and how to fix it:
First off, it's normal that you don't see a CSRF token in the request headers/cookies when fetching static files like index.html, JS, or CSS. Play doesn't automatically attach CSRF tokens to GET requests for static resources—CSRF protection is primarily designed for requests that modify server state (POST, PUT, DELETE, etc.). The key here is to make sure your Angular app can grab the CSRF token early (from the initial page load) and then attach it to all state-changing requests later.
1. Render the CSRF Token in Your Play Template
Since your Angular app is hosted by Play, you need to inject the CSRF token into the initial index.html (which should be a Play template file, not a static HTML file).
- Rename your static
index.htmltoindex.scala.htmland move it into Play'sviewsdirectory. - Add a meta tag to the
<head>section that outputs the CSRF token using Play's template helper:<meta name="csrf-token" content="@csrfToken.value"> - Update your Play route to serve this template instead of the static file:
GET / controllers.HomeController.index() - In your
HomeController, return the template (make sure to pass the implicit request so the CSRF token is available):def index() = Action { implicit request => Ok(views.html.index()) }
2. Configure Angular to Use the Token
Now that the token is in the page's meta tags, create an Angular HTTP interceptor to automatically attach it to all state-changing requests:
- Create a
csrf.interceptor.tsfile:import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable() export class CsrfInterceptor implements HttpInterceptor { intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { // Grab the token from the meta tag const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'); // Only add the token to non-GET/HEAD/OPTIONS requests (the ones that need CSRF protection) if (csrfToken && !req.method.match(/GET|HEAD|OPTIONS/)) { const modifiedRequest = req.clone({ headers: req.headers.set('X-CSRF-Token', csrfToken) }); return next.handle(modifiedRequest); } return next.handle(req); } } - Register the interceptor in your
AppModule:import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { CsrfInterceptor } from './csrf.interceptor'; @NgModule({ providers: [ { provide: HTTP_INTERCEPTORS, useClass: CsrfInterceptor, multi: true } ] }) export class AppModule { }
3. Verify Play's CSRF Configuration
Double-check your application.conf to ensure Play is set up to recognize the token header:
play.filters.csrf { token.name = "X-CSRF-Token" # Matches the header we're sending from Angular cookie.name = "PLAY_CSRF_TOKEN" # For development, you can disable secure cookies if you're not using HTTPS cookie.secure = false }
- You don't need to worry about CSRF tokens on static asset requests (GET for JS/CSS/HTML)—those are safe from CSRF attacks by design.
- If you were expecting the token to be in a cookie, Play will set the
PLAY_CSRF_TOKENcookie automatically when you render the template with the@csrfToken()helper, but using the meta tag + interceptor is the cleaner approach for Angular apps.
Give these steps a shot, and let me know if you hit any roadblocks!
内容的提问来源于stack exchange,提问作者Manu Chadha

