先上解决办法
package com.mengruan.webbackage.config;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.context.annotation.Configuration;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @program: hst-website
* @Description: shiro拦截导致跨域
* @Author: zzy
* @create: 2020-04-26 12: 34
*/
@Configuration
public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
/**
* 在访问controller前判断是否登录,返回json,不进行重定向。
* @param request
* @param response
* @return true-继续往下执行,false-该filter过滤器已经处理,不继续执行其他过滤器
* @throws Exception
*/
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
if (isAjax(request)) {
httpServletResponse.setCharacterEncoding("UTF-8");
httpServletResponse.setContentType("application/json");
//解决一下跨域问题
httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
httpServletResponse.setHeader("Access-Control-Allow-Methods", "*");
httpServletResponse.setHeader("Access-Control-Max-Age", "0");
httpServletResponse.setHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With,userId,token");
httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpServletResponse.setHeader("XDomainRequestAllowed","1");
httpServletResponse.getWriter().flush();
httpServletResponse.getWriter().close();
} else {
/**
* @Mark 非ajax请求重定向为登录页面
*/
//httpServletResponse.sendRedirect("/login");
}
return false;
}
//解决OPTIONS请求跨域问题
@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);
}
private boolean isAjax(ServletRequest request){
String header = ((HttpServletRequest) request).getHeader("X-Requested-With");
if("XMLHttpRequest".equalsIgnoreCase(header)){
return Boolean.TRUE;
}
return Boolean.FALSE;
}
}
在shiro配置类配置进去
shiroFilterFactoryBean.getFilters().put("authc", new MyFormAuthenticationFilter());
但此时上传文件还是会不成功,因为shiro包装了request 所有关于multipart请求都被拦截了 ,所以我们需要将文件上传路径不做拦截,或者将request 强转为 MultipartHttpServletRequest
// <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
filterChainDefinitionMap.put("/companydynamic/**", "authc");
filterChainDefinitionMap.put("/customerexample/**", "authc");
filterChainDefinitionMap.put("/messageboard/**", "authc");
filterChainDefinitionMap.put("/moudle/**", "authc");
filterChainDefinitionMap.put("/navigationimg/**", "authc");
filterChainDefinitionMap.put("/solutionproject/**", "authc");
//filterChainDefinitionMap.put("/uploadfile/**", "authc");//文件上传路径
以上代码是shiro用于拦截请求的,但是配置了springboot跨域以后,访问以上链接仍然会跨域。因为浏览器在访问服务端是会先发起一个method为OPTIONS的请求,这个请求我们可以简单理解为一个探路请求, 该请求不携带信息, 只是为了测试一下目标服务器是否支持跨域,如果支持跨域的话,再发出后续的请求。
而shiro配置了拦截以后,会预先拦截此OPTIONS请求,然而此OPTIONS并未携带token或者cookie,shiro会鉴权失败,导致浏览器认为服务端不支持跨域。