zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    luogu P3128 [USACO15DEC]最大流Max Flow (树上差分)
    codeforces 600E . Lomsat gelral (线段树合并)
    bzoj 1483: [HNOI2009]梦幻布丁 (链表启发式合并)
    bzoj 1257: [CQOI2007]余数之和 (数学+分块)
    codevs 2606 约数和问题 (数学+分块)
    bzoj 2038: [2009国家集训队]小Z的袜子(hose) (莫队)
    bzoj 1086: [SCOI2005]王室联邦 (分块+dfs)
    bzoj 4542: [Hnoi2016]大数 (莫队)
    【NOIp模拟赛】Tourist Attractions
    【NOIp模拟赛】String Master
  • 原文地址:https://www.cnblogs.com/red-star/p/14273163.html
Copyright © 2011-2022 走看看