第一部分.csrf问题会致使ajax请求失败,缘由是没有验证csrf的token。具体流程是启用csrf后,全部http请求都被会CsrfFilter拦截,而CsrfFilter中有一个私有类DefaultRequiresCsrfMatcher ,在这个类里面,POST方法被排除在外了,也就是说只有GET|HEAD|TRACE|OPTIONS这4类方法会被放行,其它Method的http请求,都要验证_csrf的token是否正确,而一般post方式调用rest服务时,又没有_csrf的token,因此校验失败。具体方法是重写一个Matcher,当请求为POST请求时添加一个排除校验的url列表。html
解决办法:前端
一、在jsp页面的head标签内添加以下代码:
<meta name="_csrf" content="${_csrf.token}"/>
<!-- default header name is X-CSRF-TOKEN -->
<meta name="_csrf_header" content="${_csrf.headerName}"/>ajax
二、在ajax请求前添加以下代码:
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
$(document).ajaxSend(function(e, xhr, options) {
xhr.setRequestHeader(header, token);
});spring
等同下面:json
var header = $("meta[name='_csrf_header']").attr("content"); app
var token = $("meta[name='_csrf']").attr("content"); jsp
$.ajax({ async
url: '/test', post
type: 'POST', ui
beforeSend: function(xhr){
xhr.setRequestHeader(header, token);
},
success: function(data) {
console.log(data);
},
error:function(xhr,ajaxOptions, thrownError) { console.log(xhr.status + ": " + thrownError);
} });
<sec:csrfMetaTags/>
等同于:
<head><meta name="_csrf" content="${_csrf.token}"/><meta name="_csrf_header" content="${_csrf.headerName}"/></head>
1.前端无form表单,在头部增长两个meta标签
<html> <head> <meta name="_csrf" th:content="${_csrf.token}" content=""/> <!-- default header name is X-CSRF-TOKEN --> <meta name="_csrf_header" th:content="${_csrf.headerName}" content=""/> <!-- ... --> </head>
2.前端有form表单
Spring Security为Thymeleaf中的表单中自动添加一个<input type="hidden" name = "_csrf" value="xxxxxxxxxx"> (xxxx为crrf.token)
var token = $("meta[name='_csrf']").attr("content"); var header = $("meta[name='_csrf_header']").attr("content");
$.ajax({ type: "POST", url: "myposturl", data: entID, contentType:"application/json; charset=utf-8", headers : {header:token}, async:false, success:function(data){ //do something }, error: function () { //deal width error } });
这里header里面的值为"X-CSRF-TOKEN"
第二部分:验证码部分,在登录过程当中可能会加入验证码验证,此时须要作出一些改变。
第一种:自定义一个过滤器,工做在spring security的过滤器前面实现验证码的较验。
第二种:写一个filter,继承UsernamePasswordAuthenticationFilter,重写attemptAuthentication方法实现验证码的校验,若校验不成功抛出异常。
第三种:替换UsernamePasswordAuthenticationFilter这个filter来自定义校验。