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

时间:2017-08-18 22:51:03

标签: angular spring-security

我已经获得了一个Spring启动RESTful服务,Spring安全配置如下:

__dict__

&安培;

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

}

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

角:

auth.service.ts:

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

app.module.ts(注意:使用HttpClient发布请求):

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

我已经关注了this并阅读了相关文档,但似乎无法实现这一目标。

3 个答案:

答案 0 :(得分:2)

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

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

Sol: 服务器端:

  • 首先,您需要在服务器端配置csrf安全性

  • 在服务器端,您需要编写一个在浏览器上设置cookie的api(cookie内的X-CSRF令牌),而该api却没有任何抵押就被击中(禁用此api的csrf,假设api名称为/ info)

注意:/ info该API仅在首次加载angular应用时被调用一次(您需要在要加载到angular应用中的首页中添加此信息)

角侧:

  • 当应用程序加载到angular的第一页/组件上时,在oninit内,您需要将此路由称为“ / info”(您需要在angular中创建服务并在此处调用此api) 我在我的layout / navbar组件上进行了设置,因为在加载应用程序时,该组件是第一个加载的组件

  • 然后在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,标头,RequestOptions,响应,URLSearchParams}   来自“ @ angular / http”;

也许这可以帮助您,谢谢

答案 1 :(得分:0)

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

1.请确保您正在执行 POST (在LOG IN上)方法以接收CSRF-TOKEN

2.存储在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);

答案 2 :(得分:0)

如果您的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>