生成验证码
kaptcha工具生成验证码text-随机字符串kaptchaOwner-kaptchaOwner放入cookie,设置生存时间60s-(kaptchaOwner,text)放入redis,设置生存期限60s。
这个过程和session很像,sessionId放在cookie中,通过id从服务器找到对应session,而验证码放在redis中。
@RequestMapping(path = "/kaptcha",method = RequestMethod.GET)
public void getKaptcha(HttpServletResponse response){
String text=kaptchaProducer.createText();
BufferedImage image=kaptchaProducer.createImage(text);
// session.setAttribute("kaptcha",text);
String kaptchaOwner= CommunityUtil.generateUUID();
Cookie cookie=new Cookie("kaptchaOwner",kaptchaOwner);
cookie.setMaxAge(60);
cookie.setPath(contextPath);
response.addCookie(cookie);
String redisKey= RedisKeyUtil.getKapchaKey(kaptchaOwner);
redisTemplate.opsForValue().set(redisKey,text,60, TimeUnit.SECONDS);
response.setContentType("image/png");
try {
OutputStream os=response.getOutputStream();
ImageIO.write(image,"png",os);
} catch (IOException e) {
logger.error("响应验证码失败"+e.getMessage());
}
}
LoginTicket实体封装登录记录包括userid,ticket (登录凭证)、status(0登录1退出登录)、expired(登录记录有效期限)。
存放在redis的验证码的key放在cookie中,通过key获取验证码。
将登录凭证ticket放在cokkie中。
@RequestMapping(path = "/login",method = RequestMethod.POST)
public String login(String username,String password,String code,boolean rememberme,Model model,HttpServletResponse response,@CookieValue("kaptchaOwner") String kaptchaOwner){
// String kaptcha=(String)session.getAttribute("kaptcha");
String kaptcha=null;
if(StringUtils.isNotBlank(kaptchaOwner)){
String redisKey=RedisKeyUtil.getKapchaKey(kaptchaOwner);
kaptcha= (String)redisTemplate.opsForValue().get(redisKey);
}
if(StringUtils.isBlank(kaptcha)||StringUtils.isBlank(code)||!kaptcha.equalsIgnoreCase(code)){
model.addAttribute("codeMsg","验证码错误");
return "/site/login";
}
//检查账号,密码
int expiredSeconds=rememberme?REMEMBER_EXPIRED_SECONDS:DEFAULT_EXPIRED_SECONDS;
Map<String,Object> map=userService.login(username,password,expiredSeconds);
if(map.containsKey("ticket")){
Cookie cookie=new Cookie("ticket",map.get("ticket").toString());
cookie.setPath("contextPath");
cookie.setMaxAge(expiredSeconds);
response.addCookie(cookie);
return "redirect:/index";
}else {
model.addAttribute("usernameMsg",map.get("usernameMsg"));
model.addAttribute("passwordMsg",map.get("passwordMsg"));
return "/site/login";
}
}
密码:password=md5(password+5位随机字符串salt)
生成登录凭证:ticket随机字符串存redis(TicketKey,loginTicket)
public Map<String,Object>login(String username,String password,int expiredSeconds){
Map<String,Object> map=new HashMap<>();
User user=userMapper.selectByName(username);
内容合法性验证
password=CommunityUtil.md5(password+user.getSalt());
if(!user.getPassword().equals(password)){
map.put("passwordMsg","密码错误");
return map;
}
//生成登录凭证
LoginTicket loginTicket=new LoginTicket();
loginTicket.setUserId(user.getId());
loginTicket.setStatus(0);
loginTicket.setTicket(CommunityUtil.generateUUID());
loginTicket.setExpired(new Date(System.currentTimeMillis()+expiredSeconds*1000));
String redisKey= RedisKeyUtil.getTicketKey(loginTicket.getTicket());
redisTemplate.opsForValue().set(redisKey,loginTicket);
map.put("ticket",loginTicket.getTicket());
return map;
}
整个登录流程:
登录界面-生成验证法(验证法存放在redis中(随机字符串key,验证码),key存放在cookie中。)填写登录信息-发送-获取cookie中的验证码key,进行验证-内容合法性验证和密码验证(通过前台密码和后缀salt进行md5加密与数据库密码比较)-将登录凭证信息封装,存放redis(随机生成作为此次登录凭证ticket)-将ticket放在cookie中。
退出登录
获取cookie中的ticket,将redis的登录记录状态设为1