前后分离之后SpringBoot+SpringSecurity放行Swagger访问后,security跨域配置失效的问题

问题背景:

项目用的swagger生成的接口文档,同时也有security权限验证,为了方便后端自己测试,所以接口测试直接访问swagger;

但是security如果没有放行swagger的话,本地是访问不到swagger的,同时前端要访问后端接口,也有跨域问题;

 Security没有放行swagger访问的时候,用swagger请求接口会报错:

 

前后分离之后SpringBoot+SpringSecurity放行Swagger访问后,security跨域配置失效的问题_第1张图片

我这样配置SecurityConfig之后,解决了swagger访问的问题:

 


    @Override
    public void configure(WebSecurity web) throws Exception {
        // v1是接口访问前缀,注意与自己的项目区别
        web.ignoring().antMatchers("/v1/**");
        
    }

但是,前端的跨域问题又出现了, 前端报错403;

查了一下资料,

WebSecurity和HttpSecurity的区别主要是:

 

 

  1. 这两个都是继承WebSecurityConfigurerAdapter后重写的方法
  2. http.permitAll不会绕开springsecurity验证,相当于是允许该路径通过
  3. web.ignoring是直接绕开spring security的所有filter,直接跳过验证
以下是SecurityConfig配置:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MenusService menuService;

    /**
     * 设置验证信息
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        super.configure(auth);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
       // web.ignoring是直接绕开spring security的所有filter,直接跳过验证
        web.ignoring().antMatchers("/v1/**");
       
    }

    /**
     * 设置权限信息
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //主要是看UrlMatchVoter,所有的权限检查都在UrlMatchVoter
        http.cors()
                .and()
                .csrf()
                .disable()
                .authorizeRequests()
                // http.permitAll不会绕开springsecurity验证,相当于是允许该路径通过
                .antMatchers("/v1/**").permitAll()
                .accessDecisionManager(accessDecisionManager());
    }

    @Bean
    public AccessDecisionManager accessDecisionManager() {
        List collect = menuService
                .listOpen()
                .stream()
                .map(m -> new UrlGrantedAuthority(m.getUrl()))
                .collect(toList());

        List> decisionVoters
                = Arrays.asList(
                new WebExpressionVoter(),
                new UrlMatchVoter(collect));
        return new UnanimousBased(decisionVoters);
    }

    /**
     * 跨域请求配置
     *
     * @param properties 配置属性文件名
     * @return
     */
    @Bean
    public CorsConfigurationSource corsConfigurationSource(CorsProperties properties) {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(properties.getAllowedOrigins());
        configuration.setAllowedMethods(properties.getAllowedMethods());
        configuration.setAllowCredentials(properties.getAllowCredentials());
        configuration.setAllowedHeaders(properties.getAllowedHeaders());
        configuration.setExposedHeaders(properties.getExposedHeaders());
        configuration.setMaxAge(properties.getMaxAge());
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

拦截器:

public class InterceptorConfig implements HandlerInterceptor {

    private static final Logger log = LoggerFactory.getLogger(InterceptorConfig.class);


    /**
     * 进入controller层之前拦截请求
     *
     * @param request
     * @param response
     * @param o
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
        log.info("---------------------开始进入请求地址拦截----------------------------");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
      
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

 

然后是采坑的地方,这里必须重写WebMvcConfigurer的addCorsMappings(CorsRegistry corsRegistry)方法才能彻底解决问题(既能swagger访问后端接口,也能解决前端跨域问题),

WebAppConfig:

@Component
public class WebAppConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //注册自定义拦截器,添加拦截路径和排除拦截路径
        registry.addInterceptor(new InterceptorConfig()).addPathPatterns("/v1/**/**");
    }

    /**
     * 解决security下跨域失效问题,
     */
    @Override
    public void addCorsMappings(CorsRegistry corsRegistry) {
        corsRegistry.addMapping("/**")
                // 放行哪些原始域
                .allowedOrigins("*")
                // 是否发送cookie
                .allowCredentials(true)
                // 放行哪些请求
                .allowedMethods("GET", "POST", "OPTIONS", "DELETE", "PUT")
                // 放行哪些header
                .allowedHeaders("*")
                // 暴露哪些头部信息(因为跨域访问默认不能获取全部header
                .exposedHeaders("Header1", "Header2");

    }
}

 参考了这位老哥的博客http://www.jetchen.cn/spring-security-cors/#comment-450 ,但是不用按照他那样配置过滤器也可以,可以参考参考

这样配置之后就可以解决,但是记得生产环境一定要关闭swagger:前后分离之后SpringBoot+SpringSecurity放行Swagger访问后,security跨域配置失效的问题_第2张图片

关闭之后 访问swagger就是这样了:

前后分离之后SpringBoot+SpringSecurity放行Swagger访问后,security跨域配置失效的问题_第3张图片

开发的时候,改为true就可以了,可以通过读取yml配置,灵活的切换

 

如有问题,欢迎留言交流讨论

你可能感兴趣的:(spring,boot,SpringSecurity)