Security+前后端分离CSRF使用
Security默认是开启CSRF保护的,与此类似的是CORS。具体我不是很了解,只知道CORS是管理跨域资源共享使用,CSRF是保护网络攻击的。
开发环境中经常通过API post或者其他请求访问调试,这样子也就说明,可以通过http请求随意访问。因此开启CSRF保护,表示不可通过API post调试工具调试。
这样又出现了另外一个问题,前后端分离的情况下,怎么能通过CSRF调用呢?
Security是由多个过滤器组成,CSRF实现也不例外,它是由CsrfFilter这个过滤器类实现的,CsrfFilter是对保密性的请求拦截,对于(GET|HEAD|TRACE|OPTIONS)是不拦截的。tokenRepository对象是保管toekn值的
源码的处理如下图:
这里做了六步处理:
- 获取本地存储的csrfTken
- 验证是否第一个CSRF校验请求,是则创建一个csrfTken保存起来,不是下一步
- 在请求request中加入csrfTken属性值
- 如果是GET|HEAD|TRACE|OPTIONS请求,通过
- 获取request中携带的csrfToken值,名为actualToken
- 比对actualToken和csrfTken是否相同,相同通过,不同报错
因此解决办法的思路重点在request。
- 首先肯定得过滤一个不需要csrfToken的请求吧
// security配置文件,其余配置不介绍
/**
* 拦截请求后的权限设置
*
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// 网络防护忽略请求
.csrf().ignoringAntMatchers("/user/login")
}
- 这个登录请求成功后,csrfToken会保存在request中
// 在登录成功处理器中保存这个token
/**
* 获取CSRF密钥
* "csrf": {
* "headerName": "X-CSRF-TOKEN", 必须是这个作为key
* "parameterName": "_csrf", 这个key值目前不清楚为什么获取不到值
* "token": ""
* },
* 向前端发送密钥,每次请求写在头信息中,
* 例如 X-CSRF-TOKEN: 'token',即可保证正常访问
*/
CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
- 然后将这个值传递到前端,前端保存,在每次请求头中添加这个值即可验证成功
this.axios.post(`${API_HOST}/login`, obj, {
headers: {
'X-CSRF-TOKEN': token
}
}).then(function(response) {
const data = response.data;
}, function(response) {});