前言
HTTP是一种无状态(协议对于事务处理没有记忆能力,每次的请求都是独立的,服务器端没有保存客户端的状态,客户端每次都需要带上自己的状态去请求服务器。)的协议,为了分辨链接是谁发起的,需自己去解决这个问题。不然有些情况下即使是同一个网站每打开一个页面也都要登录一下。而Session和Cookie就是为解决这个问题而提出来的两个机制。
联系:
存储数据量方面:session 能够存储任意的 java 对象,cookie 只能存储 String 类型的对象
1、Cookie和Session都是会话技术,Cookie是运行在客户端,Session是运行在服务器端。
2、Cookie有大小限制以及浏览器在存cookie的个数也有限制,Session是没有大小限制和服务器的内存大小有关。
3、Cookie有安全隐患,通过拦截或本地文件找得到你的cookie后可以进行攻击。
4、Session是保存在服务器端上会存在一段时间才会消失,如果session过多会增加服务器的压力。
Session对象
浏览器访问服务器时,服务器会创建一个对象(该对象也称为session对象,该对象有一个唯一的id号与其对应)。然后
,服务器会将id号发送给浏览器(默认情况下,使用cookie机制发送)。当浏览器再次访问服务器时,会将id号发送过
来。服务器可以依据id号找到对应的session对象。通过这个session对象,来保存状态
Cookie对象
浏览器向服务器发送请求时,服务器会将少量的数据返回给浏览器(该数据以set-cookie消息头的形式返回给浏览器)
,浏览器会将这些数据存放到硬盘或者内存上。当浏览器下次再次访问服务器时,会将之前存放的数据发送给服务器(
以cookie消息头的形式发送给服务器)。通过这种方式,就可以记录浏览器与服务器之间交互的数据,也就是状态。
项目中Session的用法
注意:下面的存储的时候都重新new HttpSessionSessionStrategy()
1.把相关的数据放入到session中去
@RestController
public class ValidateCodeController {
//设置session中的session_key,方便后期取出
private static final String SESSION_KEY ="SESSION_KEY_IMAGE_CODE";
public static String getSessionKey() {
return SESSION_KEY;
}
private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
@GetMapping("/code/image")
public void createCode(HttpServletRequest request,HttpServletResponse response) throws IOException {
//1.根据随机数生成图片
ImageCode imageCode = createImageCode();
//2.将随机数存到Session中
sessionStrategy.setAttribute(new ServletWebRequest(request),SESSION_KEY,imageCode);
//3.在将生成的图片写到接口的响应中。
ImageIO.write(imageCode.getImage(),"JPEG",response.getOutputStream());
}
将存储的数据取出来
/**
* OncePerRequestFilter:spring中提供的一个容器,保证这个过滤器只被调用一次。
* @Description TODO
* @Author Mr.Wu
* @Date 2019/8/22 20:23
* @Version 1.0
**/
public class ValidateCodeFilter extends OncePerRequestFilter {
private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
private AuthenticationFailureHandler authenticationFailureHandler;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
if(StringUtils.equals("/authentication/form",request.getRequestURI())&&
StringUtils.equalsIgnoreCase(request.getMethod(),"post")){
try {
validate(new ServletWebRequest(request));
} catch (ValidateCodeException e) {
//用我们自定义的失败处理器,来处理异常。
authenticationFailureHandler.onAuthenticationFailure(request,response,e);
}
}
filterChain.doFilter(request,response);
}
/**
* 图片验证码的验证逻辑
* @param request
*/
private void validate(ServletWebRequest request) throws ServletRequestBindingException {
//将之前存储到session中的验证码取出来,HttpSession中取值和存值使用的就是getAttribute/set
ImageCode codeInSession= (ImageCode)sessionStrategy.getAttribute(request, ValidateCodeController.getSessionKey());
//将用户写的(提交表单)的验证码提取出来
String codeInRequest = ServletRequestUtils.getStringParameter(request.getRequest(),"imageCode");
if(StringUtils.isBlank(codeInRequest)){
throw new ValidateCodeException("验证码的值不能为空");
}
if(codeInSession==null){
throw new ValidateCodeException("验证码不存在");
}
if(codeInSession.isExpired()){
sessionStrategy.removeAttribute(request,ValidateCodeController.getSessionKey());
throw new ValidateCodeException("验证码已经过期");
}
if(!StringUtils.equals(codeInSession.getCode(),codeInRequest)){
throw new ValidateCodeException("验证码不匹配");
}
sessionStrategy.removeAttribute(request,ValidateCodeController.getSessionKey());
}
}
项目中存储Cookie的用法
强转类型是向下进行转型,接口的话,一般强转为它的实现类。
private void saveCookie(String token){
//RequestContextHolder顾名思义,持有上下文的Request容器
HttpServletResponse response = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse();
CookieUtil.addCookie(response,cookieDomain,"/","uid",token,0,false);
}