Shoir导致axios出现跨域导致报错的解决方法 ShiroAxios跨域
- 创建时间:2024-08-30 / 最新修改时间:2024-08-30 11:47:09
- 344
- 0
转载请注明本文出处:http://limpire.cn/artifact/programming/java/235.html
Shoir导致Axios出现跨域导致报错的解决方法
Shoir 是需要cookies支持的,所以Axios一般都会:
//允许携带Cookies,AXIOS 会自动管理Cookies
const axiosInstance = axios.create({
withCredentials: true,
baseURL: baseUrl
})
withCredentials: true
后,服务端需要返回指定详细的 http 头 access-control-allow-origin: http://xxxxxx
.
换句话说,Controller中不能再这么写 @CrossOrigin("*")
.
那么我们可以 @CrossOrigin("http://xxxxxx")
。
设置后我发现2个现象:
- 没有被Shoir拦截的url可以正常访问
- 被Shoir拦截的的url依旧提示 Cross 的错误。
原因和解决方法
假设这个地址 用 "authc" 过滤器过滤
filterMap.put("/home/**","authc");
而authc默认的过滤器没有对Cross进行处理,所以导致前端出现错误.
那么我可以重写这个过滤器,并重新注册.
继承FormAuthenticationFilter
重写两个方法
public class CorsAuthenticationFilter extends FormAuthenticationFilter {
@Override
protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object mappedValue) {
boolean b = super.isAccessAllowed(servletRequest, servletResponse, mappedValue);
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpServletRequest request = (HttpServletRequest) servletRequest;
AccessLog.writeLog(request);//打印日志
if (b || request.getMethod().equalsIgnoreCase("OPTIONS")){
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, If-Modified-Since, x-token");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
// response.setHeader("Access-Control-Max-Age", "7600");
response.setHeader("Access-Control-Allow-Credentials", "true");
return true;
}
return b;
}
@Override
protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpServletRequest request = (HttpServletRequest) servletRequest;
String origin = request.getHeader("Origin");
response.setHeader("Access-Control-Allow-Origin", origin);
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, If-Modified-Since, x-token");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
// response.setHeader("Access-Control-Max-Age", "7600");
response.setHeader("Access-Control-Allow-Credentials", "true");
//跳转到首页
//response.sendRedirect(origin);
response.setStatus(200);
PrintWriter writer = response.getWriter();
writer.print("no login");
writer.close();
return false;
// return super.onAccessDenied(request, response);
}
}
创建 ShiroFilterFactoryBean
时注册过滤器,覆盖默认的authc
过滤器
@Bean("shiroFilterFactoryBean")
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
//新建拦截过滤器的工厂类(生产不同的拦截器,拦截请求)
ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器(处理请求的认证授权)
filterFactoryBean.setSecurityManager(defaultWebSecurityManager);
Map<String,String> filterMap = new LinkedHashMap<String,String>();
//自定义过滤器,用于处理跨域问题
CorsAuthenticationFilter corsAuthenticationFilter = new CorsAuthenticationFilter();
Map<String, Filter> filters = filterFactoryBean.getFilters();
filters.put("authc",corsAuthenticationFilter); ///!!!!!!!!******这里是重点******* 覆盖原版 authc 过滤器
filterMap.put("/user/login","anon");//anon 设置为公共资源
filterMap.put("/user/register","anon");//anon 设置为公共资源
filterMap.put("/home/**","authc");
filterFactoryBean.setFilterChainDefinitionMap(filterMap);
//设置其他配置信息
//默认的认证登陆页面(认证失败时自动跳转)
filterFactoryBean.setLoginUrl("/");
//设置未授权提示页面
filterFactoryBean.setUnauthorizedUrl("/");
return filterFactoryBean;
}
现在 Shoir 的跨域问题搞定了,但是没有被Shoir过滤的URL每一次Contoller都要添加详细 @CrossOrigin("http://xxxxxxxx")
注解,很麻烦。那么我们可以这样做,实现 servelt 的 Filter .
/**
* 解决跨域问题,用于非拦截的url
* @date 2024/8/28 17:07
*/
@Component
public class CorsFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpServletRequest request = (HttpServletRequest) servletRequest;
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, If-Modified-Since, x-token");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
// response.setHeader("Access-Control-Max-Age", "7600");
response.setHeader("Access-Control-Allow-Credentials", "true");
AccessLog.writeLog(request);//打印日志
filterChain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
总结:
使用后端验证框架Shoir和前端Axios 做项目时需要处理2个问题
- 需要解决当携带cookies时,服务端返回的头必须有详细的
access-control-allow-origin
,不能是*号。 - Shoir 默认的过滤器需要重写,主要是添加返回头的
access-control-allow-origin
信息逻辑。