Spring-Curity 前后端分离 - 跨域处理

各种问题卡了一段时间,下面正文开始

前端
  • 配置axios,使其允许携带Cookie
// 创建axios实例
const service = axios.create({
  // api 的 base_url
  baseURL: process.env.BASE_API,
  // 请求超时时间
  timeout: 60000,
  //允许携带Cookie
  withCredentials: true
})
  • 跨域设置
dev: {
  ... ...
  proxyTable: {
    '/': {
      //后端地址
      target: 'http://localhost:9000',
      changeOrigin: true,
      pathRewrite: {
        '^/': ''
      }
    }
  },
  ... ...
}
后端配置
  • 实现WebMvcConfigurer接口,重写addCorsMappings方法,如下图所示
  /**
   * 添加跨域支持
   */
  override fun addCorsMappings(registry: CorsRegistry) {
    if ("dev".equals(env)) {
      registry.addMapping("/**")
              .allowedOrigins("*")
              .allowCredentials(true)
              .allowedMethods("*")
              .exposedHeaders("Access-Control-Allow-Origin:$vueHost",
                      "Access-Control-Allow-Headers:$vueHost",
                      "Authorization",
                      "X-Requested-With")
              .maxAge(1728000)
    }
  }

vueHost的值为前端的地址,如http://localhost:9090,不要配置成*,前端会有错误,类似于:

Failed to load http://localhost:9090/user/list: The value of the ‘Access-Control-Allow-Origin’ header in the response must not be the wildcard ‘*’ when the request’s credentials mode is ‘include’. Origin ‘http://localhost:9000’ is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

  • 继承WebSecurityConfigurerAdapter类,重写configure(HttpSecurity http)方法,添加如下代码
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    AuthenticationSuccessHandler succHandler = (httpServletRequest, httpServletResponse, authentication) -> {
      if ("dev".equals(env)) {
        httpServletResponse.setHeader("Access-Control-Allow-Origin", vueHost);
      }

      this.writeResponseJson(httpServletResponse, new ObjectMapper().writeValueAsString(new MySecurityResponse(HttpCodeUtil.SUCCESS.getCode(), "", null)));
    };
    AuthenticationFailureHandler failHandler = (httpServletRequest, httpServletResponse, authenticationException) -> {
      if ("dev".equals(env)) {
        httpServletResponse.setHeader("Access-Control-Allow-Origin", vueHost);
      }
      this.writeResponseJson(httpServletResponse,
              new ObjectMapper().writeValueAsString(new MySecurityResponse(HttpCodeUtil.FAILURE.getCode(), "用户名或密码错误", null)));
    };
    LogoutSuccessHandler logoutSuccHandler = (httpServletRequest, httpServletResponse, authentication) -> {
      if ("dev".equals(env)) {
        httpServletResponse.setHeader("Access-Control-Allow-Origin", vueHost);
      }
      this.writeResponseJson(httpServletResponse,
              new ObjectMapper().writeValueAsString(new MySecurityResponse(HttpCodeUtil.SUCCESS.getCode(), "登出成功", null)));
    };
    
    if ("dev".equals(env)) {
      http.cors().and().csrf().disable();
    }
    http
            //所有的预请求都直接通过
            .authorizeRequests()
            .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            ... ...
            
            .and()
            .formLogin()
            ...
            .successHandler(succHandler)
            .failureHandler(failHandler)

            .and()
            .logout()
            ...
            .logoutSuccessHandler(logoutSuccHandler)            

            //权限不足自定义处理器
            .and()
            .exceptionHandling().accessDeniedHandler(new MyAccessDeniedHandler())
  • 实现AccessDeniedHandler接口的handle方法:
@Override
  public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
    logger.info("[Access denied] {} --- {}", request.getRequestURL(), SecurityContextHolder.getContext().getAuthentication());
    logger.info("", response);

    response.setContentType("application/json;charset=utf-8");
    try (PrintWriter out = response.getWriter()) {
      out.write(new ObjectMapper().writeValueAsString(new MySecurityResponse(HttpCodeUtil.ACCESSDENDIE.getCode(), HttpCodeUtil.ACCESSDENDIE.getCodeDesc(), null)));
    } catch (IOException e) {
      logger.error("MyAccessDeniedHandler: ", e);
    }

  }

此配置是为了在访问权限不足的资源时,直接返回一个302状态的response(这些也可以交给前端去维护。)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值