跨域问题的解决
使用springboot整合了shiro框架,springboot解决跨域的方法也是网上的到处都是的配置CORS解决跨域问题。
出现的问题:
使用了shiro框架,开启了shiro的登陆验证过滤器时,即filterChainDefinitionMap.put("/**","user");
,代表要登陆过才能进行访问,但是经过一番测试,发现当ajax请求为复杂请求时,cookie无法被携带传输到服务器的,导致一直无法访问。
在网上找了很久,大部分网友说复杂请求时若要带cookie则allowedOrigins
不能配置为“*”,而要是访问的地址,虽然可以通过配置过滤器来实现,当是本地的html还是访问不了,一直报跨域错误,而布置在不同端口的html虽然能够访问,当是cookie依旧传不了。。。
最后发现之所以传不了cookie是因为shiro的权限控制,由于复杂请求要传两次,第一次验证请求(OPTIONS
)是没有带cookie的所以验证不通过,导致接下来的真实请求无法继续,因为上面的请求被拒绝了啊。。。
解决思路:
1.可以自定义shiro的UserFilter来让OPTIONS请求无条件通过(shiro的自带的fliter都是可以通过继承来进行重写)
样例如下:
/** * 重写shiro的UserFilter,实现通过OPTIONS请求 * @author MDY */ public class
ShiroUserFilter extends UserFilter { /** * 在访问过来的时候检测是否为OPTIONS请求,如果是就直接返回true
*/ @Override protected boolean preHandle(ServletRequest request,
ServletResponse response) throws Exception { HttpServletResponse httpResponse =
(HttpServletResponse) response; HttpServletRequest httpRequest = (
HttpServletRequest) request; if (httpRequest.getMethod().equals(RequestMethod.
OPTIONS.name())) { setHeader(httpRequest,httpResponse); return true; } return
super.preHandle(request,response); } /** * 该方法会在验证失败后调用,这里由于是前后端分离,后台不控制页面跳转 *
因此重写改成传输JSON数据 */ @Override protected void saveRequestAndRedirectToLogin(
ServletRequest request, ServletResponse response) throws IOException {
saveRequest(request); setHeader((HttpServletRequest) request,(
HttpServletResponse) response); PrintWriter out = response.getWriter(); out.
println(JSONObject.toJSONString(ResultUtil.error(ExceptionEnum.IS_NOT_LOGIN)));
out.flush(); out.close(); } /** * 为response设置header,实现跨域 */ private void
setHeader(HttpServletRequest request,HttpServletResponse response){
//跨域的header设置 response.setHeader("Access-control-Allow-Origin", request.
getHeader("Origin")); response.setHeader("Access-Control-Allow-Methods", request
.getMethod()); response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers", request.getHeader(
"Access-Control-Request-Headers")); //防止乱码,适用于传输JSON数据 response.setHeader(
"Content-Type","application/json;charset=UTF-8"); response.setStatus(HttpStatus.
OK.value()); } }
2.由于博主的项目是不怎么用得到权限控制,shiro关于url的权限控制可有可无,所以博主干脆把
filterChainDefinitionMap.put("/**","user");去掉,这样子所有人都能访问。
但是如果你使用了shiro的其它url权限控制,如身份验证之类的以及shiro的权限控制注解,如果你没有登陆则会抛出
UnauthenticatedException
异常,这时可以使用全局异常控制捕获该异常,将出错信息传回前端,虽然这样子解决不是很优雅。。。(关于全局异常处理网上也有很多教程,也可以看这篇
<https://blog.csdn.net/madonghyu/article/details/79644132>)
最后附上在网上找到的springboot解决跨域问题的代码
/** * 解决跨域问题springboot所需配置 */ @Configuration public class CORSConfiguration {
@Bean public WebMvcConfigurer CORSConfigurer() { return new
WebMvcConfigurerAdapter() { @Override public void addCorsMappings(CorsRegistry
registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("*")
.allowedHeaders("*") //设置是否允许跨域传cookie .allowCredentials(true) //设置缓存时间,减少重复响应 .
maxAge(3600); } }; } }
PS:博主发现sprinboot配置之后前端不用特殊的配置就能进行跨域,不知是不是浏览器的问题还是,但为了保险起见,ajax请求时还是加上
crossDomain:true,xhrFields: { withCredentials: true },
比较好。如果要带上cookie跨域,则必须加上上面两句。
请求样例:
$.ajax({ async:true, type:"post", url:"", data:JSON.stringify(params),
contentType: "application/json; charset=utf-8", crossDomain:true, xhrFields: {
withCredentials: true }, dataType:"json", success:function(data){ console.log(
params); console.log(data); }, error:function(data){ console.log(data) } })
热门工具 换一换