前後分離之後SpringBoot+SpringSecurity放行Swagger訪問後,security跨域配置失效的問題

問題背景:

項目用的swagger生成的接口文檔,同時也有security權限驗證,爲了方便後端自己測試,所以接口測試直接訪問swagger;

但是security如果沒有放行swagger的話,本地是訪問不到swagger的,同時前端要訪問後端接口,也有跨域問題;

 Security沒有放行swagger訪問的時候,用swagger請求接口會報錯:

 

我這樣配置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<UrlGrantedAuthority> collect = menuService
                .listOpen()
                .stream()
                .map(m -> new UrlGrantedAuthority(m.getUrl()))
                .collect(toList());

        List<AccessDecisionVoter<? extends Object>> 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:

關閉之後 訪問swagger就是這樣了:

開發的時候,改爲true就可以了,可以通過讀取yml配置,靈活的切換

 

如有問題,歡迎留言交流討論

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章