• Shiro+SpringBoot前后端分离中跨域,sessionId,302问题


    1.解决跨域
    @Configuration
    public class CorsConfig {
        public CorsConfiguration buildConfig() {
            CorsConfiguration corsConfiguration = new CorsConfiguration();
            corsConfiguration.addAllowedOrigin("*"); //允许任何域名
            corsConfiguration.addAllowedHeader("*"); //允许任何头
            corsConfiguration.addAllowedMethod("*"); //允许任何方法
            return corsConfiguration;
        }
    
        @Bean
        public CorsFilter corsFilter() {
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", buildConfig()); //注册
            return new CorsFilter(source);
        }
    }
    2.解决sessionId不一致问题,配置shiro,重写获取sessionId方法
    //自定义的 shiro session 缓存管理器,用于跨域等情况下使用 token 进行验证,不依赖于sessionId(在shiroConfig中添加)
    @Bean
    public DefaultWebSessionManager getDefaultWebSessionManager() {
        MySessionManager defaultWebSessionManager = new MySessionManager();
        defaultWebSessionManager.setSessionDAO(new MemorySessionDAO());
        return defaultWebSessionManager;
    }
    
    //shiro 的 session 管理(单独写一个类)
    //自定义session规则,实现前后分离,在跨域等情况下使用token 方式进行登录验证才需要,否则没必须使用本类。
    //(shiro默认使用 ServletContainerSessionManager 来做 session 管理,它是依赖于浏览器的 cookie 来维护 session 的,调用 storeSessionId  方法保存sesionId 到 cookie中)。
    //为了支持无状态会话,我们就需要继承 DefaultWebSessionManager
    //自定义生成sessionId 则要实现 SessionIdGenerator
    
    public class MySessionManager extends DefaultWebSessionManager {
        private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
    
        public MySessionManager() {
            super();
        }
    
        @Override
        protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
            String id = WebUtils.toHttp(request).getHeader("Access-Token");
            //如果请求头中有 token 则其值为sessionId
            if (!StringUtils.isEmpty(id)) {
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
                return id;
            } else {
                //否则按默认规则从cookie取sessionId
                return super.getSessionId(request, response);
            }
        }
    }
    3.解决登录302问题
    public class UserAuthenticationFilter extends FormAuthenticationFilter {
        /**
         * 直接过滤可以访问的请求类型
         */
        private static final String REQUET_TYPE = "OPTIONS";
    
        public UserAuthenticationFilter() {
            super();
        }
    
        @Override
        public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
            if (((HttpServletRequest) request).getMethod().toUpperCase().equals(REQUET_TYPE)) {
                return true;
            }
            return super.isAccessAllowed(request, response, mappedValue);
        }
    
        /**
         * 解决302
         * @param request
         * @param response
         * @throws Exception
         */
        @Override
        protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
            if (isLoginRequest(request, response)) {
                if (isLoginSubmission(request, response)) {
                    return executeLogin(request, response);
                } else {
                    return true;
                }
            }else {
                //解决 WebUtils.toHttp 往返回response写数据跨域问题
                HttpServletRequest req =  WebUtils.toHttp(request);
                String origin = req.getHeader("Origin");
                HttpServletResponse resp = WebUtils.toHttp(response);
                resp.setHeader("Access-Control-Allow-Origin", origin);
                //通过对 Credentials 参数的设置,就可以保持跨域 Ajax 时的 Cookie
                //设置了Allow-Credentials,Allow-Origin就不能为*,需要指明具体的url域
                resp.setHeader("Access-Control-Allow-Credentials", "true");
                // 返回固定的JSON串
                ObjectMapper mapper = new ObjectMapper();
                WebUtils.toHttp(response).setContentType("application/json; charset=utf-8");
                WebUtils.toHttp(response).getWriter().print(mapper.writeValueAsString(100));
                return false;
            }
    
        }
    
    }
    4.解决权限不足302问题
    public class UserAuthorizationFilter extends PermissionsAuthorizationFilter {
        /**
         * 根据请求接口路径进行验证
         * @param request
         * @param response
         * @param mappedValue
         * @return
         * @throws IOException
         */
        @Override
        public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
            // 获取接口请求路径
            String servletPath = WebUtils.toHttp(request).getServletPath();
            mappedValue = new String[]{servletPath};
            return super.isAccessAllowed(request, response, mappedValue);
        }
    
        /**
         * 解决权限不足302问题
         * @param request
         * @param response
         * @return
         * @throws IOException
         */
        @Override
        protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
            Subject subject = getSubject(request, response);
            if (subject.getPrincipal() != null) {
                return true;
            } else {
    
                //解决 WebUtils.toHttp 往返回response写数据跨域问题
                HttpServletRequest req = (HttpServletRequest) request;
                String origin = req.getHeader("Origin");
                HttpServletResponse resp = (HttpServletResponse) response;
                resp.setHeader("Access-Control-Allow-Origin", origin);
                //通过对 Credentials 参数的设置,就可以保持跨域 Ajax 时的 Cookie
                //设置了Allow-Credentials,Allow-Origin就不能为*,需要指明具体的url域
                resp.setHeader("Access-Control-Allow-Credentials", "true");
    
                WebUtils.toHttp(response).setContentType("application/json; charset=utf-8");
                WebUtils.toHttp(response).getWriter().print("401");
            }
            return false;
        }
    
    }

     参考:https://blog.csdn.net/wmy_0707/article/details/100118329?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-3&spm=1001.2101.3001.4242 

                https://blog.csdn.net/China_hdy/article/details/97154272

  • 相关阅读:
    2013-10-31 《问题儿童居然一天两更!?》
    2013-10-31 《October 31st, 2013》
    2013-10-31 《三天里什么都没干……总之把目前为止的代码发了吧……》
    日怎么没人告诉我这博客可以改博文界面的显示宽度的
    俗话说打脸哦不打铁要趁热所以记录下替换图片的方法
    GUI好看码难写不是难写是难看我是说码难看不是GUI
    虽然保持了连续代码生产量但是仔细想想也没什么必要
    重写了电话本代码全面更新居然连续三天每天一个程序
    专注写字典三十年问你怕未又被编码卡了简直难以置信
    我就写个字典居然卡了两天重申一遍文字编码日你大爷
  • 原文地址:https://www.cnblogs.com/red-star/p/14273163.html
Copyright © 2020-2023  润新知