21.Shiro在springboot与vue前后端分离项目里的session管理

摘要:
最后,在成功登录后,前端接收从后端返回的sessionId并将其存储在cookie中。稍后,当前端向后端发送请求时,请求头将携带sessionid。后端代码通过解析sessionid获得正确的会话。
1.前言

当决定前端与后端代码分开部署时,发现shiro自带的session不起作用了。

然后通过对请求head的分析,然后在网上查找一部分解决方案。

最终就是,登录成功之后,前端接收到后端传回来的sessionId,存入cookie当中。

之后,前端向后端发送请求时,请求Head中都会带上这个sessionid。

后端代码通过对这个sessionid的解析,拿到正确的session。

2.代码改造

(1)后端代码改造

  1. 添加CustomSessionManager.java

    /**
     * 类的详细说明
     *
     * @author 郭广明
     * @version 1.0
     * @Date 2018/11/3014:56
     */
    public class CustomSessionManager extends DefaultWebSessionManager {
    
        /**
         * 获取请求头中key为“Authorization”的value == sessionId
         */
        private static final String AUTHORIZATION ="Authorization";
    
        private static final String REFERENCED_SESSION_ID_SOURCE = "cookie";
    
        /**
         *  @Description shiro框架 自定义session获取方式<br/>
         *  可自定义session获取规则。这里采用ajax请求头 {@link AUTHORIZATION}携带sessionId的方式
         */
        @Override
        protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
            // TODO Auto-generated method stub
            String sessionId = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
            if (StringUtils.isNotEmpty(sessionId)) {
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sessionId);
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
                return sessionId;
            }
            return super.getSessionId(request, response);
        }
    
    }
    
  2. 改造ShiroConfig.java

    @Configuration
    public class ShiroConfig {
    
        @Autowired
        private UserService userService;
    
        @Bean
        public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    
            // 必须设置 SecurityManager
            shiroFilterFactoryBean.setSecurityManager(securityManager);
    
            // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
            shiroFilterFactoryBean.setLoginUrl("/login");
    
            // 拦截器.
            Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
            // 配置不会被拦截的链接 顺序判断
            filterChainDefinitionMap.put("/static/**", "anon");
            filterChainDefinitionMap.put("/doLogin", "anon");
            filterChainDefinitionMap.put("/swagger-resources", "anon");
            filterChainDefinitionMap.put("/v2/api-docs", "anon");
            filterChainDefinitionMap.put("/webjars/**", "anon");
            filterChainDefinitionMap.put("/swagger-ui.html", "anon");
    
            // <!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
            // <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
            filterChainDefinitionMap.put("/**", "anon");
    
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
            System.out.println("Shiro拦截器工厂类注入成功");
            return shiroFilterFactoryBean;
        }
    
        /**
         * 注入MyRealm
         * @return
         */
        @Bean
        public SecurityManager securityManager() {
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            // 设置realm.
            securityManager.setSessionManager(sessionManager());
            securityManager.setRealm(myShiroRealm());
            return securityManager;
        }
    
        /**
         * 配置注解
         * @param securityManager
         * @return
         */
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor
                    = new AuthorizationAttributeSourceAdvisor();
            authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
            return authorizationAttributeSourceAdvisor;
        }
    
        @Bean
        public MyRealm myShiroRealm() {
            return new MyRealm(userService);
        }
    
        @Bean("sessionManager")
        public SessionManager sessionManager(){
            CustomSessionManager manager = new CustomSessionManager();
    		/*使用了shiro自带缓存,
    		如果设置 redis为缓存需要重写CacheManager(其中需要重写Cache)
    		manager.setCacheManager(this.RedisCacheManager());*/
    
            manager.setSessionDAO(new EnterpriseCacheSessionDAO());
            return manager;
        }
    
    }
    

(2)前端代码改造

  1. 添加CookieUtil.js

    export default {
    	setCookie: (name,value,days) =>{
    		var d = new Date;
    		d.setTime(d.getTime() + 24*60*60*1000*days);
    		window.document.cookie = name + "=" + value + ";path=/;expires=" + d.toGMTString();
    	},
    	getCookie: name =>{
    		var v = window.document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)');
    		return v ? v[2] : null;
    	},
    	delCookie: name =>{
    		this.setCookie(name, '', -1); //将时间设置为过去时,立即删除cookie
    	}
    	
    }
    
  2. 改造HttpUtil.js

    import axios from 'axios'
    import doCookie from '@/util/cookieUtil'
    
    axios.defaults.headers.common['Authorization'] = doCookie.getCookie("SESSIONID")
    axios.defaults.baseURL = 'http://127.0.0.1:8080'
    
    
    /**
     * Get请求
     */
    export function get(url, callback){
        axios.get(url)
        .then(function (response) {
            if(response.data.length==0 || response.data==null) {
                callback(null,true)
            } else {
                callback(response.data,true)
            }
        })
        .catch(function (error) {
            callback(null,false)
        })
    }
    
    export function remove(url, callback){
        axios.delete(url)
        .then(function (response) {
            if(response.data.length==0 || response.data==null) {
                callback(null,true)
            } else {
                callback(response.data,true)
            }
        })
        .catch(function (error) {
            callback(null,false)
        })
    }
    
    export function post(url, data, callback){
        axios.post(url,data)
        .then(function (response) {
            if(response.data.length==0 || response.data==null) {
                callback(null,true)
            } else {
                callback(response.data,true)
            }
        })
        .catch(function (error) {
            callback(null,false)
        })
    }
    
    export function put(url, data, callback){
        axios.put(url,data)
        .then(function (response) {
            if(response.data.length==0 || response.data==null) {
                callback(null,true)
            } else {
                callback(response.data,true)
            }
        })
        .catch(function (error) {
            callback(null,false)
        })
    }
    
    
    export default {
        get,
        post,
        put,
        remove,
    }
    

免责声明:文章转载自《21.Shiro在springboot与vue前后端分离项目里的session管理》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇OneNote如何使用yum install --downloadonly 下载依赖包研究下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

vue中ref的使用(this.$refs获取为undefined)

如果你获取到的总是空的,你注意一下: 1、你在哪里调用,和你调用的对象 试试在mounted()里面调用有效果没有 调用的对象是本来就存在的,还是需要数据渲染之后才会出现的,同理,在mounted()里面调用看看 2、调用对象是不是数组列表 我一开始设置ref在v-for列表上,直接获取this.$refs.name.style,永远是空的, 后来才发现,...

vue 公用组件开发 确认框confirm

文件目录: github地址:https://github.com/xingkongwuyu/vue-spa-experience/tree/master/src/components 最终的效果:  组件的源码解析: confirm :  confirm的框架 ./index.js import confirmBox from './src/inde...

Spring MVC使用ModelAndView进行重定向

1、Servlet重定向forward与redirect: 使用servlet重定向有两种方式,一种是forward,另一种就是redirect。forward是服务器内部重定向,客户端并不知道服务器把你当前请求重定向到哪里去了,地址栏的url与你之前访问的url保持不变。redirect则是客户端重定向,是服务器将你当前请求返回,然后给个状态标示给你...

boost asio 异步实现tcp通讯

---恢复内容开始--- asioboost 目录(?)[-] 一前言 二实现思路 通讯包数据结构 连接对象 连接管理器 服务器端的实现 对象串行化 一、前言 boost asio可算是一个简单易用,功能又强大可跨平台的C++通讯库,效率也表现的不错,linux环境是epoll实现的,而windows环境是iocp实现的。而tcp通讯是项...

浅析vue实例的生命周期(生命周期钩子)

“每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等” ,在不同的生命周期内会经历不同的钩子函数(生命周期函数),这就提供了将我们自己的代码写入的机会。如果将生命周期比作人的话,生命周期就是一个人的一生,生命钩子函数就相当于人的不同年龄段(幼年、青年、中年、老年)...

几种常见的微服务架构方案简述——ZeroC IceGrid、Spring Cloud、基于消息队列

微服务架构是当前很热门的一个概念,它不是凭空产生的,是技术发展的必然结果。虽然微服务架构没有公认的技术标准和规范草案,但业界已经有一些很有影响力的开源微服务架构平台,架构师可以根据公司的技术实力并结合项目的特点来选择某个合适的微服务架构平台,以此稳妥地实施项目的微服务化改造或开发进程。本文选自《架构解密:从分布式到微服务》一书,了解本书详情请点击阅读原文。...