最近在写一个 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;
    }