栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

请你说说cookie、session和token的概念和区别

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

请你说说cookie、session和token的概念和区别

文章目录
  • 前言
  • 一、session和cookie
    • 1.1Web发展史
    • 1.2session和cookie
    • 1.3session认证缺点
  • 二、基于token的鉴权机制
  • 总结


前言

http协议本身是一种无状态的协议,我们并不能知道是哪个用户发出的请求,因此产生了Web身份校验问题。cookie、session和token都是为了解决Web身份校验而产生的,初学者往往搞不清三者的概念和区别,本篇文章带大家解析这三者的区别和概念。


一、session和cookie 1.1Web发展史

1、很久以前,Web基本上就是文档的浏览而已, 既然是浏览,作为服务器, 不需要记住是谁请求的,每次请求都是一个新的HTTP协议。

2、但是随着交互式Web应用的兴起,像在线购物网站,需要登录的网站等等,需要管理会话,必须记住哪些人登录系统,哪些人往自己的购物车中放商品, 也就是说我必须把每个人区分开。

解决办法:
给大家发一个会话标识(session id), 说白了就是一个随机的字串,每个人收到的都不一样,每次大家向我发起HTTP请求的时候,把这个字符串给一并捎过来, 这样我就能区分开谁是谁了,这就是所谓的session认证。

1.2session和cookie

session :就是会话。这个就类似于你和一个人交谈,你怎么知道当前和你交谈的是张三而不是李四呢?对方肯定有某种特征(长相等)表明他就是张三。服务器就要给每个客户端分配不同的“身份标识”,然后客户端每次向服务器发请求的时候,都带上这个“身份标识”,服务器就知道这个请求来自于谁了。至于客户端怎么保存这个“身份标识”,可以有很多种方式,对于浏览器客户端,大家都默认采用 cookie 的方式。

cookie:非常具体的东西,指的就是浏览器里面能永久存储的一种数据,仅仅是浏览器实现的一种数据存储功能。cookie由服务器生成,发送给浏览器,浏览器把cookie以kv形式保存到某个目录下的文本文件内,下一次请求会把该cookie发送给服务器。

区别:cookie数据存放在客户的浏览器上,session数据放在服务器上。将重要信息存放在Session中,其他信息如果需要保留,可以放在cookie中。

session认证流程如下:

1、当用户首次访问服务器的时候,服务器为每个用户单独创建一个 Session 对象,并分配一个新的 SessionID,此时 SessionID 通过 cookie 保存在用户端。

2.当用户再次访问服务器的时候,携带保存 SessionID 的 Cookie 给服务器,服务器查询是否存在这个 sessionID,如果存在,即认为用户处于登录状态,如果没有对应的 SessionID,服务器会给分配一个新的 sessionID。

关于session认证代码如下:
1.如果登录成功(账号密码验证成功),往session中存放manage键值对。

public class ControllerLogin {
    @Autowired
    LoginService loginService;

    @RequestMapping(value ="/login")
    public CommonMessage test(Manage manage, HttpSession httpSession) {
        try {
            Manage manageTemp = loginService.login(manage);

            if (manageTemp != null) {
                httpSession.setAttribute("manage", manageTemp);
                return new CommonMessage(200, "登录成功", manageTemp);
            } else {
                return new CommonMessage(300, "登录失败",(Manage)null);
            }
        } catch (Exception e) {
            return new CommonMessage(301, "登录失败", (Manage)null);
        }
    }
  }

2.session认证代码部分,使用拦截器,请求到达之前判断是否处于登录状态(即有没有manage属性值)

public class LoginInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession httpSession=request.getSession();
        Manage manage = (Manage) httpSession.getAttribute("manage");
        if(manage !=null){
            return  true;
        }else{
            response.getWriter().println(203);
            return  false;
        }
    }
    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}
1.3session认证缺点

1.session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大。
2.用户下一次请求还必须在第一次请求的服务器上(只有第一次访问的服务器保存了Session信息),在分布式的应用上,相应的限制了负载均衡器的能力。
3.cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。


二、基于token的鉴权机制

基于Token的身份验证是无状态的,我们不将用户信息存在服务器或Session中,解决了在服务端存储信息时的许多问题。

流程:
1.用户通过用户名和密码发送请求。
2.程序验证,并返回一个签名的token 给客户端。
3.客户端储存token,并且每次用于每次发送请求。
4.服务端验证token并返回数据。

token由三部分组成:
1.第一部分头部(header):声明加密算法(HMAC -HS256)
2.第二部分我们称其为载荷(payload ):保存用户的信息
3.第三部分是签名(signature):需要base64转码后的header和base64转码后的payload连接组成的字符串,然后通过header中声明的加密方式进行加密。

token令牌如何让别人伪造不了?
1.用HMAC-SHA256算法,加上密钥,对数据做一个签名,把这个签名和数据一起作为token, 由于密钥别人不知道,就无法伪造token了。

2.当客户端把这个token发过来的时候,再用同样的HMAC-SHA256算法和同样的密钥,对数据再计算一次签名, 和token中的签名做个比较, 如果相同,就知道客户端已经登录过了,如果不相同,数据部分肯定被人篡改过,则告诉客户端没有认证。

token认证优点:
1.无状态、可扩展:服务器只是生成token , 然后验证token,基于这种无状态和不存储Session信息,负载负载均衡器能够将用户信息从一个服务传到其他服务器上。
2.安全:作为身份认证token安全性比session好,因为每个请求都有签名。

token认证的代码如下:
1.token工具类,用来创建生成token、验证token有效性和获得token 中playload部分数据。

public class TokenUtil {
   
    public static String token (Integer id, String account,Integer type){
        String token = "";
        try {
            //过期时间 为1970.1.1 0:0:0 至 过期时间  当前的毫秒值 + 有效时间
            Date expireDate = new Date(new Date().getTime() + 10000*1000);
            //秘钥及加密算法
            Algorithm algorithm = Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE");
            //设置头部信息
            Map header = new HashMap<>();
            header.put("typ","JWT");
            header.put("alg","HS256");
            //携带id,账号信息,生成签名
            token = JWT.create()
                    .withHeader(header)
                    .withClaim("id",id)
                    .withClaim("account",account)
                    .withClaim("type",type)
                    .withExpiresAt(expireDate)
                    .sign(algorithm);
        }catch (Exception e){
            e.printStackTrace();
            return  null;
        }
        return token;
    }
    
    public static boolean verify(String token){
        try {
            //验签
            Algorithm algorithm = Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE");
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception e) {//当传过来的token如果有问题,抛出异常
            return false;
        }
    }
   
    public static DecodedJWT getTokenInfo(String token){
        return JWT.require(Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE")).build().verify(token);
    }
}

2.拦截器,每次请求到达之前判断token是否有效。

public class LoginInterceptor implements HandlerInterceptor {
     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String toke =request.getHeader("token");
        boolean flag=TokenUtil.verify(toke);
        if(flag){
            return  true;
        }else{
            response.getWriter().println(401);
            return  false;
        }
    }
}

3.登录控制器,如果登录成功,则把id,账号名等需要的信息存储在token中,然后放在实体manage中,前端可以直接获取到token然后存储在浏览器中,下次发请求之前把token也一起发送过来即可。

@RestController
@RequestMapping("/api/login")
public class BackLoginController {
    @Autowired
    AdminService adminService;
    @RequestMapping("/login")
    public CommonResult login(@RequestBody Manage manage){
        CommonResult commonResult=null;
        try {
            Manage manage1= adminService.login(manage);

            if (manage1!=null){
                String token= TokenUtil.token(manage1.getId(),manage1.getAccount(),manage1.getType());
                manage1.setToken(token);
                commonResult=new CommonResult(200,"登录成功",manage1);
                return commonResult;
            }else {
                commonResult=new CommonResult(201,"账号或密码错误",null);
                return commonResult;
            }

        } catch (Exception e) {
            e.printStackTrace();
            commonResult=new CommonResult(500,"服务器忙",null);
            return commonResult;
        }
    }
}

总结

理解cookie、session和token的关键在于它们三者都是为了解决web身份验证而诞生的。session保存在服务器端,cookie和token保存在客户端,从这个方面入手可以联想出很多区分点。建议不要死记硬背这三者的概念和区别,要从认证流程出发思考它们之间的关系。


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/984154.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号