苦苦挣扎了一段时间 . 我在后端使用带有Spring安全性(启用Cors-filter)的Java / J2EE(RESTFul)使用Angular.js . Spring尝试完全正常,除非我尝试启用csrf保护 . 下面是我为csrf尝试的代码:
我的CSRF过滤器
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);
}
}
安全配置有以下代码:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.formLogin()
.successHandler(authSuccess)
.failureHandler(authFailure)
.and()
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.antMatchers("/admin/**").access("hasRole('ADMIN')")
.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
.and()
.addFilterBefore(corsFilter, HeaderWriterFilter.class)
.addFilterAfter(csrfHeaderFilter, CsrfFilter.class)
.csrf().csrfTokenRepository(csrfTokenRepository());
//.csrf().disable();
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
必须修改CORS过滤器以在Access-Control-Allow-Headers中添加X-XSRF-TOKEN标头名称,因为它最初提供此错误 .
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "X-XSRF-TOKEN, x-requested-with, Content-Type");
chain.doFilter(req, res);
}
我的角度js代码:
$scope.login = function () {
$http.post("http://localhost:9090/cynosureserver/login", "username=" + $scope.user.name +
"&password=" + $scope.user.password, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-XSRF-TOKEN': $cookies.get('XSRF-TOKEN')
}
}).then(function (data) {
alert("login successful" + JSON.stringify(data));
}, function (err) {
alert("error logging in" + JSON.stringify(err));
});
};
我有调试点设置 . 登录后,它将转到Csrf过滤器 . 但从来没有打过我的“CustomUserDetailsService” . 问题是我总是得到403回复说:
HTTP状态403 - 未找到预期的CSRF令牌 . 你的会话已经过期了吗?
如果我发出一个简单的Get请求它就会成功,并且在Response Header中也会收到“XSRF-TOKEN”cookie .
但对于我的帖子方法,我无法继续 . 我在下面看到:
Status Code:403 Forbidden
Remote Address:[::1]:9090
响应 Headers
Access-Control-Allow-Headers:X-XSRF-TOKEN, x-requested-with, Content-Type
Access-Control-Allow-Methods:POST, GET, PUT, OPTIONS, DELETE
Access-Control-Allow-Origin:*
....
Set-Cookie:JSESSIONID=5DE6DB8B5E31DC77DC4ED28600445615; Path=/cynosureserver/; HttpOnly
X-Content-Type-Options:nosniff
X-Frame-Options:DENY
X-XSS-Protection:1; mode=block
请求 Headers
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate
...
Content-Type:application/x-www-form-urlencoded
Host:localhost:9090
Origin:http://localhost:9000
Referer:http://localhost:9000/
X-XSRF-TOKEN:7c2057b5-0f1a-4dc1-bab4-c8f000a2ae2d
表格数据
username:manisha
password:123456
我尝试了很多不同的组合,但似乎没有任何效果,请帮帮我 - 我错过了什么?我在这里完全无能为力 . 对不起冗长的帖子 .