简单的CAS单点登录
程序员文章站
2022-06-11 11:19:59
...
使用Redis+cookie实现简单的单点登录
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));
}