Angular 4 无法在标题中设置 CSRF-TOKEN

Posted

技术标签:

【中文标题】Angular 4 无法在标题中设置 CSRF-TOKEN【英文标题】:Angular 4 can't set CSRF-TOKEN in header 【发布时间】:2018-01-27 16:35:57 【问题描述】:

我有一个 Spring boot RESTful 服务,其 Spring 安全配置如下:

protected void configure(HttpSecurity httpSecurity) throws Exception 
        httpSecurity.cors().and()
                /*.formLogin().loginPage("/auth")
                .permitAll().and()
                .authorizeRequests()
                .anyRequest()
                .authenticated()
                .and().httpBasic().and()*/
                .csrf()
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .and()
                .addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class);
    

&

public class CsrfHeaderFilter extends OncePerRequestFilter 

private static final String CSRF_COOKIE_NAME = "XSRF-TOKEN";

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException 

    CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
    if (csrf != null) 
        response.addHeader("X-CSRF-TOKEN", csrf.getToken());
        Cookie cookie = WebUtils.getCookie(request, CSRF_COOKIE_NAME);
        String token = csrf.getToken();

        if (cookie == null || token != null && !token.equals(cookie.getValue())) 
            cookie = new Cookie(CSRF_COOKIE_NAME, token);
            cookie.setPath("/");
            response.addCookie(cookie);
        
    

    filterChain.doFilter(request, response);

我正在使用 Angular 4(最新版本)调用 RESTful 服务。它正在发出一个抱怨并抛出 403 Forbidden “无法验证提供的 CSRF 令牌,因为找不到您的会话”。这是预期的,因为我在发送 post 请求时没有设置 X-CSRF-TOKEN 标头,但此标头确实存在:- 设置 Cookie:XSRF-TOKEN=;路径=/

角度:

auth.service.ts:

const body = 'SOMERANDOMKEY1111';

const headers = new HttpHeaders().set('Content-Type', 'application/json').set('withCredentials', 'true');

    return this._http.post(this.endpoint + this.auth, body, 
      headers: headers
    );

app.module.ts(注意:使用 HttpClient 进行 post 请求):

providers: [ ...

    provide: XSRFStrategy, useFactory: xsrfFactory
...]
export function xsrfFactory() 
  return new CookieXSRFStrategy('XSRF-TOKEN', 'XSRF-TOKEN');

我已关注 this 并阅读了文档,但似乎无法正常工作。

【问题讨论】:

角码在哪里? 用角码更新。 参考这个How to send "Cookie" in request header for all the requests in Angular2? 我已经在设置 ​​withCredentials 标题但仍然无法正常工作。 似乎重复:***.com/questions/43364213/… 【参考方案1】:

当我开始使用 Spring 和 angular5 时,我遇到了同样的问题:

问:如何在 angular 发出的每个请求上设置 X-CSRF 令牌?

溶胶: 服务器端:

首先你需要在服务器端配置csrf安全

在服务器端,您需要编写一个在浏览器上设置 cookie 的 api(cookie 中的 X-CSRF 令牌),并且此 api 在没有任何证券的情况下命中(在此 api 上禁用 csrf,假设 api 名称/信息)

注意:/info 这个 api 仅在 Angular 应用第一次加载时被调用一次(您需要在第一页中添加这是要在 Angular 应用中加载的)

角边:

当应用程序在 angular 的第一页/组件上加载时,在 oninit 中您需要调用此路由“/info”(您需要在 angular 中创建服务并在那里调用此 api) 我在我的布局/导航栏组件上设置了这个,因为当加载应用程序时,这个组件是第一个加载的组件

然后在 app.module.ts 内部我们需要导入

从 '@angular/common/http' 导入 HttpClientModule ;

并将这个模块添加到导入数组中:

@NgModule(   imports: [
                     HttpClientXsrfModule.withOptions(
                     cookieName: 'XSRF-TOKEN',
                     headerName: 'X-XSRF-TOKEN',
         )]

-然后在服务内部你需要改变请求如下:user.service.ts

 registeruser(data) 
    console.log(data)
    let headers = new Headers( 'Content-Type': 'application/json' );
    let options = new RequestOptions( headers: headers, withCredentials: true );
    return this.http.post(this.url + '/avssymbuaa/api/register', data, options).map(res => res.json());
  
注意:你需要在服务上导入这个

import Http, Headers, RequestOptions, Response, URLSearchParams 来自“@angular/http”;

也许这个对你有帮助,谢谢

【讨论】:

【参考方案2】:

响应被禁止,因为 spring 服务器或您的代理预计会在标头中接收 X-CSRF 令牌,而您没有发送它。

1.请确保您正在执行 POST(登录时)方法来接收 CSRF-TOKEN

2.将收到的token存储在cookies或localstorage

3. 发帖并将令牌添加到标题中,如下所示:

let headers = new Headers( 'XSRF-TOKEN', 'the token received after login' );
let options = new RequestOptions( headers: headers );
return this.http.post(url,body,options);

【讨论】:

也许我不是很清楚。对不起。我更新了帖子【参考方案3】:

如果您的Angular UI 和 RESTful 服务位于不同的域中,您的 Angular 代码将无法读取后端设置的 cookie。要在本地工作区解决这个问题,您可以set up cli proxy 但是对于生产来说,如果你使用的是 Apache HTTP 服务器,你需要设置反向代理。这是一个例子:

对于 https

<VirtualHost *:443>
    ServerName localhost
    SSLEngine on
    SSLProxyEngine On
    SSLCertificateFile conf/ssl/newfile.crt
    SSLCertificateKeyFile conf/ssl/newfile.key
    ProxyPass /api/ https://yoursite/api/
    ProxyPassReverse /api/ https://yoursite/api/
</VirtualHost>

对于http

<VirtualHost *:80>
    ServerName localhost
    ProxyPass /api/ http://yoursite/api/
    ProxyPassReverse /api/ http://yoursite/api/
</VirtualHost>

【讨论】:

以上是关于Angular 4 无法在标题中设置 CSRF-TOKEN的主要内容,如果未能解决你的问题,请参考以下文章

Angular 4:在innerHTML中设置img src base href

如何在 Angular 4 的 contenteditable div 中设置插入符号位置?

如何在IONIC 4中设置rootPage

在 keycloak-Angular 中设置客户端密码

如何在材料设计 Angular 6 中设置时间选择器?

在Angular2的选择列表中设置最初选择的项目