Shoir导致axios出现跨域导致报错的解决方法 ShiroAxios跨域
- 创建时间:2024-08-30 / 最新修改时间:2024-08-30 11:47:09
- 787
- 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
信息逻辑。