spring security 跨域请求防护
跨域请求攻击(csrf):一个站点欺骗用户提交请求到其他服务器
spring security从3.2开始默认开启csrf防护,post请求不包含csrf oken或者token与后端的值不一致,会抛出csrf异常;
如果使用thymeleaf模版,在form中的action属性中添加命名空间前缀“th_”,则会自动添加隐藏域“_csrf”
********************
示例
******************
service 层
CustomUserDetailsService
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Resource
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
String username="gtlx";
String password=passwordEncoder.encode("123456");
List<GrantedAuthority> authorities=new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return new User(username,password,authorities);
}
}
******************
config 层
WebConfig
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login/form").setViewName("login");
registry.addViewController("/logout/success").setViewName("logout");
registry.addViewController("/hello2/form").setViewName("hello2");
}
}
WebSecurityConfig
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin().loginPage("/login/form").loginProcessingUrl("/login")
.and().authorizeRequests()
.antMatchers("/hello").hasAuthority("ROLE_USER")
.antMatchers("/**").permitAll()
.and().logout().logoutUrl("/logout").invalidateHttpSession(true)
.deleteCookies("JSESSIONID").logoutSuccessUrl("/logout/success");
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(initPasswordEncoder());
}
@Bean
public PasswordEncoder initPasswordEncoder(){
return new BCryptPasswordEncoder();
}
}
******************
controller 层
HelloController
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello(Principal principal){
return "hello "+principal.getName();
}
@RequestMapping("/hello2")
public String hello2(String name){
return "hello "+name;
}
}
******************
前端页面
hello2.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org" xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form th:action="@{/hello2}" method="post" th:align="center">
name:<input type="text" name="name"><br>
<button>提交</button>
</form>
</body>
</html>
********************
使用测试
localhost:8080/hello2/form
开启csrf防护功能后,默认添加隐藏域
name:瓜田李下,输出:hello 瓜田李下
如果直接在postman中,name:瓜田李下,则会报错:
默认开启跨域防护,postman发送的post请求不包含csrf token,因而报错