springboot(shiro)+vue(axios)跨域问题记录

1. 通用设置

一旦前后端分离,就涉及到跨域问题(域名、端口、协议(http或https等)其一不一样就是跨域)。
在涉及到跨域问题时,浏览器发送请求前,会优先发送一个OPTION请求。
所以,对于springboot项目,只需要自定义一下web过滤器即可。

/**
 * 解决跨域问题
 */
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("http://xx.xx.xx.xx:port")
                .allowCredentials(true)
                .maxAge(3600)
                .allowedHeaders("Accept", "Content-Type", "Origin", "Authorization", "X-Auth-Token")
                .exposedHeaders("X-Auth-Token", "Authorization")
                .allowedMethods("POST", "GET", "DELETE", "PUT", "OPTIONS");
    }
}

说明:

  • allowedOrigins:一般情况下配置"*"和配合"ip:port"都行,但是在某些情况下,出现后者可以,前者不行的问题。故先建议配成具体的ip(*后续再试即可)。
  • allowCredentials:普通跨域,这个值无所谓,true或false都可以。(但是有shiro认证,必须为true,下文再说)
  • allowedHeaders、allowedMethods:允许OPTION即可。
    经过上述一个配置即可,前端也不需要任何配置,如前端:
let instance = axios.create({
  baseURL: host,
  timeout: 120000
})
2. 携带cookie的跨域

shiro用户认证在浏览器cookie中存在JSESSIONID信息,发送请求时,会携带信息。因此,需要前端和后端,都需要设置允许Credentials。

前端设置

加一条设置,如:

let instance = axios.create({
  baseURL: host,
  timeout: 120000
})
instance.defaults.withCredentials = true
后端设置

也只需要在前述的WebConfig类中修改一条配置:

WebConfig
...
.allowCredentials(true)
...

至此,shiro + axios跨域初步解决。

初步解决的问题有哪些呢?shiro认证拦截已经生效,未登录情况下,访问被拦截。登录之后,不会被拦截。如:
/login接口:

    @GetMapping("/login")
    public RootRespBody<Boolean> login() {
        Subject subject = SecurityUtils.getSubject();
        if(!subject.isAuthenticated()){
            return RootRespBody.failure(RootRespBody.Status.ACCESS_DENIED, "please login", false);
        }
        return RootRespBody.success(true);
    }

登录后访问直接成功:

{"status":200,"message":"SUCCESS","data":true}

3. shiro + vue

上述配置在shiro + vue的项目中并不能正常使用,原因是跨域时,请求会发送两个,一个OPTION, 一个正常的请求。
在这里插入图片描述
通常是OPTIONS Reqeust正常返回status 200,然后才发起正式的GET/POST等访问,但因为Shiro配置了URL过滤, 对于OPTIONS Request也进行了拦截,OPTION是没有携带cookie信息的,所以无法继续访问,后续实际的请求也就不会发送。
在这里插入图片描述
上述截图只发送了OPTION请求,由于该请求没通过,没有发送真正的需要的请求。

解决方法:shiro配置,允许OPTION不经过过滤器。

public class MyAuthenticationFilter extends FormAuthenticationFilter {
    /**
     * @desc  跨域时,先发送option请求,option是不携带cookie信息的,但是也被shiro拦截了导致不通过,无法发送正常请求
     *        因此需要将OPTION放行。
     * @param request
     * @param response
     * @param mappedValue
     * @return
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        if (request instanceof HttpServletRequest) {
            if (((HttpServletRequest) request).getMethod().toUpperCase().equals("OPTIONS")) {
                return true;
            }
        }
        return super.isAccessAllowed(request, response, mappedValue);
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response)
            throws Exception {
        WebUtils.toHttp(response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
        return false;
    }
}

在shiro 配置中手动加上:

		//以下两行配合MyAuthenticationFilter过滤器使用
		Map<String, Filter> filterMap = shiroFilterFactoryBean.getFilters();
		filterMap.put("authc", new MyAuthenticationFilter());

至此,完成!
其他:后续可以考虑重定向的优化。
参考:
https://www.jianshu.com/p/e56362315581

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值