浅谈Session和Token


前言

HTTP协议本身是无状态协议

无状态:同一个客户端的多次请求,服务器并不能识别此客户端的身份,例如:第2次收到此客户端的请求时,并不知道此客户端此前已经提交过一次请求,更不知道第1次处理此客户端请求时产生的数据

在开发实践中,是需要明确客户端身份的,所以,从技术层面,可以使用Session和Token来解决HTTP协议无状态的问题


一、Session是什么?

1.简介

Session:会话

Session的本质是一个MAP结构的数据,当客户端首次向服务器提交请求时,服务端会响应一个Session ID到客户端,客户端在后续的访问中,都会在请求中自动携带此Session ID,同时,服务器的内存中会存在每个Session ID对应的session数据,从而,每个客户端都可以访问到自己的此前存入的数据

由于Session是在服务器端的内存中的数据,因此,默认情况下,并不适合于集群系统,更不适用于分布式系统

2.使用方法

下面将代入实际的业务演示如何使用:

a.处理用户登录请求的业务中,验证登录成功时,调用Session对象的setAttribute()方法,将登录成功的用户对象保存到会话对象里面

@RequestMapping("/login")
    public int login(@RequestBody User user, HttpSession session, HttpServletResponse response){
        System.out.println("user = " + user);
        User u = mapper.selectByUsername(user.getUsername());
        if(u!=null){
            if(u.getPassword().equals(user.getPassword())){
                //把登录成功的用户对象保存到会话对象里面
                session.setAttribute("user",u);
                
                return 1;
            }
            return 2;
        }
        return 3;
    }

b.调用Session对象的getAttribute()方法,取出会话对象

@RequestMapping("/currentUser")
    public User currentUser(HttpSession session){
        //取出会话对象中 登录成功时保存进去的用户对象
        User user = (User)session.getAttribute("user");
        System.out.println("user = " + user);
        return user;
    }

c.当客户端退出登录时,调用Session对象的removeAttribute()方法,删除会话对象

@RequestMapping("/logout")
    public void logout(HttpSession session){
        //删除会话对象中的user
        session.removeAttribute("user");
    }

二、Token是什么?

1.简介

Token:票据,令牌

当用户尝试登录,将请求提交到服务器端,如果服务器端认证通过,会生成一个Token数据并响应到客户端,此Token是有意义的数据,此客户端在后续的每一次请求中,都应该携带此Token数据,服务端通过解析此Token来识别用户身份

 

 

2.使用方法

JWT:JSON Web Token:使用JSON格式表示多项数据的Token

在使用JWT之前,需要在项目中添加相关的依赖,用于生成JWT和解析JWT,可参考官网:jwt.io

例如:

<!-- JJWT(Java JWT) -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

一个原始的JWT数据应该包含:

HEADER:ALGORITHM & TOKEN TYPE(算法与Token类型)

PAYLOAD(载荷):DATA

VERIFY SIGNATURE(验证签名)

下面向将放在测试类中大家演示如何使用:

public class JwtTests {

    // Secret Key
    String secretKey = "97iuFDVDfv97iuk534Tht3KJR89kBGFSBgfds";

    @Test
    public void testGenerate() {//生成JWT
        // 准备Claims值
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", 9527);
        claims.put("name", "liudehua");
        claims.put("nickname", "andy");

        // JWT的过期时间
        Date expiration = new Date(System.currentTimeMillis() + 5 * 60 * 1000);  
        //五分钟后过期
        System.out.println("过期时间:" + expiration);


        // JWT的组成:Header(头:算法和Token类型)、Payload(载荷)、Signature(签名)
        String jwt = Jwts.builder()
                // Header
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                // Payload
                .setClaims(claims)
                .setExpiration(expiration)
                // Signature
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();
        System.out.println("JWT=" + jwt);

        /*eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoibGl1ZGVodWEiLCJuaW
        NrbmFtZSI6ImFuZHkiLCJpZCI6OTUyNywiZXhwIjoxNjYyNDYzMzcyfQ.GW6aDBTc5ZZh
        PbsaqPeP3MNaMN2e6jjlzX_VZdqtwR8*/
    }


    @Test
    public void testParse() {//解析JWT
        // 注意:必须使用相同secretKey生成的JWT,否则会解析失败
        // 注意:不可以使用过期的JWT,否则会解析失败
        // 注意: 使用过期的JWT,也会解析失败
        // 注意:复制粘贴此JWT时,不要带“尾巴”,否则会解析失败
        // 注意:不可以恶意修改JWT中的任何字符,否则会解析失败
        String jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoibGl1ZGVodW" +
                "EiLCJuaWNrbmFtZSI6ImFuZHkiLCJpZCI6OTUyNywiZXhwIjoxNjYyNDYzMzcyfQ" +
                ".GW6aDBTc5ZZhPbsaqPeP3MNaMN2e6jjlzX_VZdqtwR8";
        Claims claims = Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(jwt)
                .getBody();
        Integer id = claims.get("id", Integer.class);
        String name = claims.get("name", String.class);
        String nickname = claims.get("nickname", String.class);
        System.out.println("id = " + id);
        System.out.println("name = " + name);
        System.out.println("nickname = " + nickname);
    }

}

总结

关于Session和Token:Session默认是保存在服务器的内存中的数据,会占用一定得服务器内存资源,并且,不适合集群或分布式系统(虽然可以通过共享Session)来解决,客户携带的Session ID只具有唯一性的特点(理论上),不具备数据含义......而Token的本质是将有意义的数据进行加密处理后的结果,各服务器都只需要具有解析这个加密数据的功能即可获取到其中的信息含义,理论上不占用内存资源,更适用于集群和分布式系统,但是,存在一定得被解密的风险(概率极低).

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值