Angular 2:将csrf参数添加到noNgForm

时间:2017-01-15 20:53:28

标签: angular spring-security csrf csrf-protection

今天在角度SPA上从html模板提交表单时遇到了问题。 首先,提交的简单表单无法开箱即用,因为angular会抓住提交事件而不让表单提交。

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

要让angular忽略该值并让您的浏览器执行帖子,您必须添加ngNoForm标题:

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

对于SPA来说,这可能不是很常见,因为这样的表单提交会导致浏览器远离SPA,但这就是我需要的。

好事 - 我使用spring-boot作为我的后端,所以使用spring-security它有很好的csrf和cors保护,不让我提交表单。我得到例外:

  

在请求参数'_csrf'上找到无效的CSRF令牌'null'   或标题'X-CSRF-TOKEN'

那么,问题是如何为角度模板提供csrf的值?

1 个答案:

答案 0 :(得分:1)

我在JHipster框架中找到了一个很好的例子。 需要做三件事:

  1. angular2-cookie插件
  2. CSRFService
  3. 将隐藏的参数添加到表单
  4. 添加angular2-cookie插件非常简单:

    npm install angular2-cookie --save
    

    但是,您需要将所有必需的映射添加到SystemJS或您使用的任何模块框架。对于SystemJS,一切都解释得非常好here。仔细阅读,因为我第一次忘了做:

    import { CookieService } from 'angular2-cookie/services/cookies.service';
    
    @NgModule({
      providers: [ CookieService ],
    })
    export class AppModule { }
    

    现在,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);
        }
    }
    

    现在,您需要将其注入呈现模板的组件:

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

    最后不要忘记在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>
    

    希望,这对任何人都有帮助,因为我花了一半时间试图弄清楚如何实现我想要的目标。