最近在写一个 demo,是前后端分离的,前端通过使用 axios 来发送异步请求来获取后端的数据,后端使用了 SpringSecurity 来做系统的鉴权,但发现,SpringSecurity 总是拿不到 session 的问题。
前言:
由于 SpringSecurity 中,很多东西都是基于 session 来做的,比如,当用户登录成功后,会创建一个 SecurityContextHolder,里面存储了用户认证后的 token 数据,然后将其存储到 session 中。
当该用户的后续请求再过来时,如用户的权限鉴定,会先到 session 中把该 SecurityContextHolder 取出来,这样就不需要重复的到数据库中查询用户的数据。
问题:
axios 在发送异步请求是,无法携带 sessionid,导致后端在处理请求时,会为其创建新的的会话,所以在用户登录成功后,在下一次请求,(访问带权限的 url) 做用户鉴权时就无法获取到用户的认证信息,这样 SpringSecurity 就会提示用户未登录,访问无权限的限定的 url 是,会看到用户的角色是 “匿名的”。
解决:
想要解决这个问题也很简单,思路就是然 axios 每次发送请求时,都带上 session_id,这样后端就可以识别出这是哪个 session。
axios 的设置:
将 withCredentials 设置为 true,默认为 false。意思是允许请求时携带 cookic 信息。
因为 http 是无状态的,所以 session 信息会存放在 cookic 中,随请求携带。
import axios from 'axios'
axios.defaults.baseURL="http://localhost:8081"
//让请求携带cookic信息
axios.defaults.withCredentials=true
CORS 跨域设置
这里主要注意两个点:
1.Origin 不能使用通配符 ”*”
2.Credentials 要设置为 true
这里以 SpringSecurity 配置 CORS 为例
@Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().authenticationEntryPoint(new SmsLoginEntryPoint())
.and()
.authorizeRequests()
.antMatchers("/app/**").permitAll()
.antMatchers("/user/**").hasRole("user")
.antMatchers("/admin/**").hasRole("admin")
.and()
.formLogin().permitAll()
.and()
.cors()
.configurationSource(configurationSource()) //配置SpringSecurity的跨域问题
.and()
.csrf().disable()
.apply(smsAuthenticationSecurityConfig)
.and().addFilterBefore(new SuccessFilter(), UsernamePasswordAuthenticationFilter.class);
// .and()
// .addFilterAfter(new UserAccessSecurityFilter(), FilterSecurityInterceptor.class);
}
//配置跨域请求
CorsConfigurationSource configurationSource(){
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedHeader("*");//设置被允许的请求头字段,*表示允许所有字段
corsConfiguration.addAllowedMethod("*");//设置允许的请求方法,*表示允许所有请求方法
corsConfiguration.addAllowedOrigin("http://localhost:8080");//设置允许的域,*表示允许所有的域
corsConfiguration.setAllowCredentials(true);
corsConfiguration.setMaxAge(3600L);//设置预检请求有效期,有效期内不必再次发送预检请求,默认是1800秒
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**",corsConfiguration);
return source;
}