1.HTTP cookie session
cookie
服务器通过response带给浏览器,浏览器下次请求再次访问相同服务器时会带上。浏览器是存内存。所以关闭浏览器就会消失(除非设置存活时间)
cookie两个重要参数
1.作用路径(不可能全部路径都带上cookie)
2.设置存活时间
cookie存客户端明显不安全
// cookie示例
@RequestMapping(path = "/cookie/set", method = RequestMethod.GET)
@ResponseBody
public String setCookie(HttpServletResponse response) {
// 创建cookie
Cookie cookie = new Cookie("code", CommunityUtil.generateUUID());
// 设置cookie生效的范围
cookie.setPath("/community/alpha");
// 设置cookie的生存时间
cookie.setMaxAge(60 * 10);
// 发送cookie
response.addCookie(cookie);
return "set cookie";
}
@RequestMapping(path = "/cookie/get", method = RequestMethod.GET)
@ResponseBody
//这个注解能让我们找到对应cookie,而不是通过遍历获得
public String getCookie(@CookieValue("code") String code) {
System.out.println(code);
return "get cookie";
}
session
session的实现用到了cookie。为了分辨哪个浏览器对应哪个session。在设置session时,会给浏览器自动发送cookie,value为sessionid,找到唯一的session。安全可以存敏感数据
缺点:存在客户端内存中,会好卡。且在分布式部署时会出现session失效的问题(下面解释为什么失效)
// session示例
@RequestMapping(path = "/session/set", method = RequestMethod.GET)
@ResponseBody
public String setSession(HttpSession session) {
//自动给浏览器发送cookie
session.setAttribute("id", 1);
session.setAttribute("name", "Test");
return "set session";
}
@RequestMapping(path = "/session/get", method = RequestMethod.GET)
@ResponseBody
public String getSession(HttpSession session) {
System.out.println(session.getAttribute("id"));
System.out.println(session.getAttribute("name"));
return "get session";
}
分布式部署session失效
下面是分布式部署的样子。我们加了负载,导致浏览器带的cookie只能找到其中一个服务器的session,其他的都可能还没生成。
解决:
1.nginx策略设置为同一ip只能访问同一服务器。(这样性能太差)
2.所有服务器同步session,太占用内存
3.在设置一个专门存session的服务器,所有session都到那里去找(如果挂了,所有session失效)
4.敏感数据存数据库。数据库集群很成熟了。但是硬盘读取数据较慢。
5.存非关系型数据库,redis最佳解决方案。
2.验证码生成
生成的png返回前浏览器的方法
@RequestMapping(path = "/kaptcha", method = RequestMethod.GET)
public void getKaptcha(HttpServletResponse response, HttpSession session){
//由于我们这次返回的是图片,不是string,html所以void,response自己写
//1.调用bean生成验证码
String text = kaptchaProdecer.createText();
BufferedImage image = kaptchaProdecer.createImage(text);
//2.将验证码存入session
session.setAttribute("kaptcha",text);
//3.将图片输出给浏览器.返回图片,且是png类型的图片
response.setContentType("image/png");
try {
//springmvc管理的流,我们不用关
OutputStream outputStream = response.getOutputStream();
ImageIO.write(image,"png",outputStream);
} catch (IOException e) {
logger.error("验证码获取异常:"+e.getMessage());
}
}
3.登录登出实现
@RequestMapping(path = "/login",method = RequestMethod.POST)
public String login(String username,String password,String code,boolean remember,
Model model,HttpSession session,HttpServletResponse response){
String kaptcha = (String) session.getAttribute("kaptcha");
//检查验证码(给表现层处理)
if (StringUtils.isBlank(kaptcha) || StringUtils.isBlank(code) || !kaptcha.equalsIgnoreCase(code)){
model.addAttribute("codeMsg","验证码不正确");
return "/site/login";
}
//检查账号,密码。给业务层处理
//是否勾选记住我
int expiredSeconds = remember ? REMEMBER_EXPIRED_SECONDS : DEFAULT_EXPIRED_SECONDS;
Map<String, Object> map = userService.login(username, password, expiredSeconds);
if (map.containsKey("ticket")){
//成功,重定向到首页。把凭证当做cookie发给浏览器
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";
}
}
@RequestMapping(path = "/logout",method = RequestMethod.GET)
public String logout(@CookieValue("ticket") String ticket){
//把凭证状态改为1,禁用。并且过期时间改成点击登出的时间,就是立马过期
userService.logout(ticket);
//重定向默认发的就是get请求
return "redirect:/login";
}