AngularJS + Spring Security - 如何在POST请求中设置CSRF令牌?

时间:2016-01-25 17:35:04

标签: java angularjs spring csrf csrf-protection

在我的AngularJS authService中,我发送一个带有凭据和用户名的POST请求到一个单独的域上的服务器端点。 我有一个CORSFilter,因为我可以在SecurityConfiguration类中禁用CSRF保护时成功POST数据。

我做错了什么?如何使用POST请求发送CSRF令牌?

authService.login(凭证)

response.login = function (credentials) {
      return $http({
        method: "POST",
        dataType: "json",
        url: baseUrl + "/authenticate",
        withCredentials: true,
        data: { username: credentials.username },
        headers: {
          'Authorization' : "Basic " + btoa(credentials.username + ":" + credentials.password),
          'Content-Type': 'application/json'
        }
      });
    };

CsrfHeaderFilter

public class CsrfHeaderFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
                .getName());
        if (csrf != null) {
            Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
            String token = csrf.getToken();
            if (cookie==null || token!=null && !token.equals(cookie.getValue())) {
                cookie = new Cookie("XSRF-TOKEN", token);
                cookie.setPath("/");
                response.addCookie(cookie);
            }
        }
        filterChain.doFilter(request, response);
    }
}

SecurityConfiguration.java

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomUserDetailsService customUserDetailsService;

    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .httpBasic()
                .and()
                .authorizeRequests()
                .antMatchers("/**")
                .permitAll().anyRequest().authenticated()
                .and().csrf()
                .csrfTokenRepository(csrfTokenRepository())
                .and()
                .addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class);
//                .addFilterAfter(new CsrfHeaderFilter(), SessionManagementFilter.class);
    }

    private CsrfTokenRepository csrfTokenRepository() {
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
        repository.setHeaderName("X-XSRF-TOKEN");
        return repository;
    }

    @Override
    protected UserDetailsService userDetailsService() {
        return customUserDetailsService;
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

}

UserController中

    @RequestMapping(method = RequestMethod.POST, value = "/authenticate")
    @PreAuthorize("hasRole('ROLE_USER')")
    public @ResponseBody User login(@RequestParam String username) {

        User user = repo.getUserWithUsername(username);

        if (user == null) throw new NotFoundException();
        return user;
    }

1 个答案:

答案 0 :(得分:-1)

如果您有某种形式,请尝试此操作。 Spring会自动生成一个带有CSRF令牌的隐藏输入,您可以使用它:

function getCsrfHeader() {
var csrfToken = $("input[name='_csrf']").val();

var headers = {}; 
headers["X-CSRF-TOKEN"] = csrfToken;
headers["_csrf"] = csrfToken;
return headers;
};


function postSomethingToServer() {
var headers = getCsrfHeader();

var req = {
    method: 'POST',
    url: URL,
    headers: headers,
    data: SOME_DATA
};

$http(req)
.success(function() { ... })
.error(function() { ... });
}
相关问题