欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

简单的CAS单点登录

程序员文章站 2022-06-11 11:19:59
...

使用Redis+cookie实现简单的单点登录

简单的CAS单点登录

1:用户第一次登陆A系统,发现未登陆,会携带上returnUrl跳转至CAS系统的登陆方法,在这个方法会验证此用户是否已经登陆(具有全局会话),如果没有登陆,就会跳转至CAS登陆页面,让用户登录

	@GetMapping("/login")
    public String test(HttpServletRequest request, HttpServletResponse response,
                       Model model,String returnUrl) {
        model.addAttribute("returnUrl", returnUrl);
        // 需要判断当前用户是否在CAS登录过(获取存放在cookie中的全局会话)
        String userTicket = getCookie(request, COOKIE_USER_TICKET);
        // 判断这个会话是否有效
        boolean verifyUserTicket = verifyUserTicket(userTicket);
        if (verifyUserTicket) {
        // 如果有效则跳转至returnUrl
            String tmpTicket = setTemTicket();
            return "redirect:" + returnUrl + "?tmpTicket=" + tmpTicket;
        }

        return "login";
    }

2:用户在输入用户名,密码后,CAS校验通过了,就会创建全局会话,全局票证,临时票证(用于跳转至returnUrl后校验)

@PostMapping("doLogin")
    public String doLogin(HttpServletRequest request, HttpServletResponse response,
                          Model model, String returnUrl,String password,String username) {

        if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
            model.addAttribute("errMsg", "用户名或密码不能为空");
            return "login";
        }
        UserLoginBo userLoginBo = new UserLoginBo(username, password);
        Users users = userService.queryUsersByUsernameAndPassword(userLoginBo);
        if (users == null) {
            model.addAttribute("errMsg", "用户名或密码错误");
            return "login";
        }

        // 创建Redis会话
        String uniqueToken = UUID.randomUUID().toString().trim();
        UsersVo usersVO = new UsersVo();
        BeanUtils.copyProperties(users, usersVO);
        usersVO.setUserUniqueToken(uniqueToken);
        // Redis全局会话,(分布式)
        redisOperator.set(REDIS_USER_TOKEN + ":" + users.getId(),
                JsonUtils.objectToJson(usersVO));
        // 生成ticket全局门票,代表用户在CAS端登录过
        String userTicket = UUID.randomUUID().toString().trim();
        redisOperator.set(REDIS_USER_TICKET + ":" + userTicket,
                users.getId());

        setCookie(COOKIE_USER_TICKET, userTicket, response);
//        CookieUtils.setCookie(request, response, COOKIE_USER_TICKET, userTicket, true);

        // 生成临时的门票,用于returnUrl的验证
        String temTicket = setTemTicket();


        return "redirect:" + returnUrl + "?tmpTicket=" + temTicket;
    }

校验temticket

@PostMapping("verifyTmpTicket")
    @ResponseBody
    public IMOOCJSONResult verifyTmpTicket(String tmpTicket,HttpServletRequest request) throws Exception{
        if (StringUtils.isBlank(tmpTicket)) {
            return IMOOCJSONResult.errorMsg("请重新登录");
        }
        // 从Redis中获取临时的门票,进行验证
        String redisTmpTicket = redisOperator.get(REDIS_TMP_TICKET + ":" + tmpTicket);
        if (StringUtils.isBlank(redisTmpTicket)) {
            return IMOOCJSONResult.errorMsg("票证已经过期");
        }
        if (!redisTmpTicket.equals(MD5Utils.getMD5Str(tmpTicket))) {
            return IMOOCJSONResult.errorMsg("票证不一致");
        }
        // 表示票证么有问题,删除临时的票证
        redisOperator.del(REDIS_TMP_TICKET + ":" + tmpTicket);
        // 从CAS的cookie中获取用户信息
        String userTicket = getCookie(request, COOKIE_USER_TICKET);
        if (StringUtils.isBlank(userTicket)) {
            return IMOOCJSONResult.errorMsg("票证有问题");
        }
        String userId = redisOperator.get(REDIS_USER_TICKET + ":" + userTicket);
        if (StringUtils.isBlank(userId)) {
            return IMOOCJSONResult.errorMsg("票证有问题");
        }
        // 利用cookie中的票证去Redis中拿用户信息
        String userInfo = redisOperator.get(REDIS_USER_TOKEN + ":" + userId);
        if (StringUtils.isBlank(userInfo)) {
            return IMOOCJSONResult.errorMsg("票证有问题");
        }
        return IMOOCJSONResult.ok(JsonUtils.jsonToPojo(userInfo, UsersVo.class));
    }