问题
之前文章《Spring Security +Spring Session Redis+JJWT》介绍了怎么使用Spring Security实现restful风格的登录api。现在,我们在这个基础上面实现csrf防护措施。
csrf原理
在调用登录的接口的时候,必须在已有的基础上面携带请求头X-CSRF-TOKEN
,以验证这个请求是合法的登录请求。
Spring Security
AuthController.java
前端在调用登录接口之前,需要先调用获取token的接口。然后,再调用登录接口。
@GetMapping("/csrf")
public CsrfResponse csrf(@RequestAttribute("_csrf") CsrfToken csrf) {
return CsrfResponse.builder().token(csrf.getToken()).build();
}
CsrfResponse.java
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CsrfResponse {
private String token;
}
SecurityConfiguration.java
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.cors().and().csrf().and()
...
.requestMatchers(HttpMethod.GET, "/auth/csrf").permitAll()
....
)
...
.formLogin(withDefaults())
.httpBasic().disable();
return http.build();
}
这里主要就是添加了匿名获取csrf token的接口,并启用Spring Security CSRF防护。
注意: Spring Security的csrf默认是忽略GET请求,但是不会忽略匿名POST请求,这种需求,可以使用如下配置实现:
...
http.cors().and().csrf()
// 配置匿名post请求忽略csrf
.ignoringRequestMatchers("/xx/register")
....
测试
获取csrf token接口
调用登录接口
在普通登录的基础上面,多添加一个请求头X-CSRF-TOKEN。这个请求头的数据,就是之前调用获取csrf token接口中,获取到的数据。这样就登录成功了。
获取资源接口
这样就成功调用了一般业务接口。
总结
REST版本的csrf防护,就是在原有的登录接口基础上面,新增一个实时随机请求头来,实现CSRF防护。有点像限流中的令牌桶原理。
源码:JwtSession