简体   繁体   中英

Angular 2: add csrf parameter to noNgForm

Today faced an issue with submitting a form from an html template on angular SPA. First of all simple form with submit doesn't work out of the box since angular catches the submit event not letting the form to be submitted.

   <form action="/api/connect/facebook" method="POST">
       <input type="hidden" name="scope" value="email" />
       <button type="submit" class="btn btn-primary btn-block"><i class="icon-facebook"></i> &nbsp;&nbsp;&nbsp;Login via Facebook</button>
   </form>

To let angular ignore that and let your browser to do the post you have to add ngNoForm header:

   <form ngNoForm action="/api/connect/facebook" method="POST">
       <input type="hidden" name="scope" value="email" />
       <button type="submit" class="btn btn-primary btn-block"><i class="icon-facebook"></i> &nbsp;&nbsp;&nbsp;Login via Facebook</button>
   </form>

This may be not very common for SPA because such form submit will navigate browser away from SPA, however that's what I need.

Good thing - I am using spring-boot as my backend, so with spring-security it has nice csrf and cors protection not letting me to submit the form. I getting the exception:

Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'

So, the question is how to provide the value of csrf for angular template?

I found a nice example how this is done in JHipster framework. Three things are required:

  1. angular2-cookie plugin
  2. CSRFService
  3. Add hidden param to the form

Adding angular2-cookie plugin is as simple as:

npm install angular2-cookie --save

However you will need to add all required mappings to SystemJS or whatever module framework you use. For SystemJS everything is explained quite nice here . Read it carefully because first time I forgot to make:

import { CookieService } from 'angular2-cookie/services/cookies.service';

@NgModule({
  providers: [ CookieService ],
})
export class AppModule { }

Now, the CSRFService:

import { Injectable } from '@angular/core';
import { CookieService } from 'angular2-cookie/core';

@Injectable()
export class CSRFService {

    constructor(private cookieService: CookieService) {}

    getCSRF(name?: string) {
        name = `${name ? name : 'XSRF-TOKEN'}`;
        return this.cookieService.get(name);
    }
}

Now, you need to inject it to the component which renders your template:

import {Component, OnInit} from '@angular/core';
import {CSRFService} from './csrf.service';

@Component({
    moduleId: module.id,
    selector: 'login-form',
    templateUrl: 'login.component.html',
    styleUrls: ['login.component.css']
})
export class LoginComponent implements OnInit {

    private csrf: string;

    constructor(private csrfService: CSRFService) { }

    ngOnInit() {
        this.csrf = this.csrfService.getCSRF();
    }
}

And finally don't forget to add the hidden parameter to the form in login.component.html:

<form ngNoForm action="/api/connect/facebook" method="POST">
    <input name="_csrf" type="hidden" value="{{ csrf }}"/>
    <input type="hidden" name="scope" value="email" />
    <button type="submit" class="btn btn-primary btn-block"><i class="icon-facebook"></i> &nbsp;&nbsp;&nbsp;Login via Facebook</button>
</form>

Hope, that helps anybody, because I spent half of the day trying to figure out how to achieve what I want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM