redis缓存和cookie实现Session共享

来源:互联网 发布:2016网络最热门话题 编辑:程序博客网 时间:2024/05/29 10:26

分布式项目中要实现单点登录(SSO - Single Sign On):对于同一个客户端(例如 Chrome 浏览器),只要登录了一个子站(例如 a.com),则所有子站(b.com、c.com)都认为已经登录。
比如用户在登录淘宝后,跳转到天猫时就已经登录了。

用例步骤

未登录用户访问子站 a.com 进行登录,自动跳转到账户中心的统一登录页 account.com/login用户在统一登录页进行登录,登录成功后显示登录跳转页显示登录跳转页后自动跳转回 a.com,单点登录完成用户在访问 b.com 时无需再次登录

通过redis缓存和cookie实现单点登录

整体实现思路如下图所示。

这里写图片描述

Session的缓存机制

1.业务系统发起登录请求,调用SSO用户登录接口;

2.SSO登录接口的处理逻辑:

2.1 根据用户名和密码去数据库验证用户是否合法。2.2 用户验证通过之后,生成SessionID,并返回给业务系统。    同时以SessionID为key,存储用户信息到redis缓存中

SSO登录接口代码:

public JSONObject userLogin(@RequestBody JSONObject jsonObject){            UserLoginResponse userLoginResponss = new UserLoginResponse();            try {                logger.info("处理用户登录业务逻辑,接收报文"+jsonObject);                String msgWithDigesta=SecurityUtil.scfMatch(jsonObject.toString(), newXService.getPrivateKey());                //生成实体                User user = JSONObject.parseObject(msgWithDigesta,User.class);                //是否验证用户的密码                boolean isChechPassword = true;                User userInfo = anaService.loginCheckUserInfo(user,isChechPassword);                // 存储用户信息到redis缓存中                String ticket = anaService.storeUserLoginSessionInRedis(userInfo,user.getModuleCode());                userLoginResponss.setRetCode(RetCode.LOGIN_SUCCESS.getCode());                userLoginResponss.setRetMessage("用户登录成功");                userLoginResponss.setTicket(ticket);                userLoginResponss.setStatus(userInfo.getStatus());                userLoginResponss.setIsModifyPassword(userInfo.getIsModifyPassword());            } catch (Exception e) {                userLoginResponss.setRetCode(RetCode.LOGIN_FAILED.getCode());                userLoginResponss.setRetMessage(e.getMessage());                logger.info("插入用户数据到表中失败,原因:"+e.getMessage());            }            logger.info("返回处理用户登录业务逻辑结果,Result{[]}"+JSONObject.toJSONString(userLoginResponss));            return JSON.parseObject(JSONObject.toJSONString(userLoginResponss));        }  

存储用户信息到redis缓存的代码:

   /**        * 存储用户登录session信息到redis中        * @param userInfo        * @return        */        public String storeUserLoginSessionInRedis(User userInfo,String moduleCode) {            // 存储用户ticket信息            // 使用AES加密登录用户ID生成SessionID,加密密码是配置文件里定义的64位字符串            String sessionId = AesUtil.encrypt(String.valueOf(userInfo.getUserId()), newXService.getBizkey());            String unique_ticket = userInfo.getSystemId()+sessionId+"_USER_LOGIN";            //            String ticket = userInfo.getSystemId()+sessionId+System.currentTimeMillis()+"_USER_LOGIN";            UserLoginSession userLoginSession = new UserLoginSession();            userLoginSession.setUserId(String.valueOf(userInfo.getUserId()));            userLoginSession.setUserName(userInfo.getUserName());            userLoginSession.setUserLoginName(userInfo.getUserLoginName());            // 获取权限            List<Permission> permissions = getUserPermissions(userInfo.getUserId());            userLoginSession.setPermissions(permissions);           userLoginSession.setModuleCode(StringUtils.killNull(userInfo.getModuleCode()));            userLoginSession.setLastLoginTime(userInfo.getLastLoginTime());            userLoginSession.seteId(StringUtils.killNull(userInfo.geteId()));            userLoginSession.setSessionId(ticket);            userLoginSession.setUserInfo(userInfo);                //限制唯一登录,删除上一个用户信息            if (redisService.exists(unique_ticket))                redisService.del(redisService.get(unique_ticket));            redisService.set(unique_ticket, ticket);            logger.info("访问AnaController的login方法:放进redis"+ticket);            redisService.setKeyExpire((ticket).getBytes(),1800);            logger.info("userloginsession result ="+JSONObject.toJSONString(userLoginSession));            return ticket;        }  

3.业务系统将返回的sessionID,存放到cookie里

业务系统controller的代码:

     @RequestMapping("/login.ajax")       @ResponseBody       public  Map<String, Object> login(@RequestParam("username2") String username2,                                    @RequestParam("moduleCode2") String moduleCode2,                                    @RequestParam("password2") String password2, String requestUrl, HttpServletResponse response) {                // 其他业务逻辑省略                  String sessionId = userBySso.getTicket();                  Cookie cookie = new Cookie("CORE_SESSION", sessionId);                  cookie.setPath("/");                  response.addCookie(cookie);                  // 其他业务逻辑省略     }  

4.业务系统取得Session信息,并检验用户信息

业务系统的页面发起web请求时,在自定义拦截器(继承自HandlerInterceptor)的preHandle方法里取得session信息,并检查用户是否登录。
Session信息取得时,首先从cookie中取得SessionId,然后根据SessionId从redis取得用户信息

自定义拦截器的代码此处省略,请参照【SpringMVC学习笔记2_拦截器实现登录验证】,以下是取得session信息的代码

    public UserLoginSession getUserLoginSession(HttpServletRequest req) {            logger.info("访问getUserLoginSession");            String sessionId = "";            Cookie[] cookie = req.getCookies();            if (cookie == null) {                return null;            }            for (int i = 0; i < cookie.length; i++) {                Cookie cook = cookie[i];                if (cook.getName().equals("CORE_SESSION")) {                    sessionId = cook.getValue().toString();                }            }            logger.info("访问getUserLoginSession获取sessionId: " + sessionId);            if ("".equals(sessionId)) {                return null;            }            String UserLoginSessionStr = redisService.get(sessionId);            logger.info("访问getUserLoginSession获取USERLOGINSESSION: " + UserLoginSessionStr);            if (null == UserLoginSessionStr || "".equals(UserLoginSessionStr)) {                return null;            }            UserLoginSession userLoginSession = (UserLoginSession) JSONObject.toJavaObject(JSONObject.parseObject(UserLoginSessionStr), UserLoginSession.class);            logger.info("访问getUserLoginSession获取USER_ID成功: " + userLoginSession.getUserId());            redisService.setKeyExpire((sessionId).getBytes(), 1800);            redisService.setKeyExpire((userLoginSession.getTicketRole()).getBytes(),1800);            return userLoginSession;        }  

版权声明:本文为博主原创文章,未经博主允许不得转载。