关于cookies、session、token(JWT)的浅薄理解

关于cookies、session、token(JWT)的浅薄理解

无状态的HTTP

Web应用程序是使用HTTP协议传输数据的,而HTTP是无状态的,在一次数据通信完成后,客户端和服务器端的连接就会关闭,再一次需要通信交换数据就需要重新建立新的连接。也就是说,当前HTTP通信无从得知历史的HTTP通信交换过什么数据,这就是无状态。

Cookies

由于现在大部分的应用中需要前后的操作具有关联性,比如用户先登录了淘宝,这是一次HTTP交换,再点击购物车,这又是一次HTTP通信,但是在第二次通信的时候应用程序并不知道是谁登录了购物车,于是Cookies就出场了。当用户发起第一次HTTP请求的时候,服务器把用户的信息写进Cookie里面返回给客户端,只要这个Cookie没过期,之后每次访问这个网站都会在HTTP的头部携带这个Cookie,这样服务器接收到这个Cookie验证用户信息成功就可以获取用户登录信息而不用再次登录。Cookie是保存在客户端的,并且是不可跨域的,不安全的。

Session

Session则是另一种保存客户状态的机制,与Cookie不同的是,Session保存在服务器。客户端第一次发送HTTP请求到服务器,服务器就会创建一个Session对象,这个对象可以保存K-V组,然后服务器返回一个session_id(这个session_id是写进cookies的)给客户端。之后客户端每次请求这个网站都会通过Cookie携带这个session_id,服务器验证session_id通过就可以获取用户信息而不用再次登录。由于Session会占用服务器资源,因此设置Session过期时间很重要。

JWT(toekn)

Session-Cookies机制存在以下问题

  • 使用服务器集群时,session要同步共享到每台服务器,占用大量服务器资源
  • 前后端分离、跨域访问时,每次请求的session_id不一致
  • 如果是多端共享后端API服务,由于移动端无Cookie,这是短板

token就没有这些问题,并且更轻量级。

JWT解析

在客户端第一次发送HTTP后,服务器把用户的信息和自定义的秘钥加密生成token,然后把token返回给客户端,客户端最好把这个JWT放在HTTP请求头的Authorization字段或者放在POST的请求体中,每次访问服务器都携带这个JWT,服务器接收到JWT后,通过使用秘钥解密JWT,就能得到用户信息。

  • JWT的组成

    JWT由三部分组成:

    • 头部(header,包含类型和算法等信息)
    • 负载(payload,存放有效信息,比如用户信息,不要存放重要信息比如密码)
    • 签证(signature,由BASE64加密后的header和payload连接起来,通过header中指定的加密方式,组合秘钥进行加密形成)
  • Spring Boot的实现

    pom.xml

    <!-- JWT -->
    <dependency>
    	<groupId>com.auth0</groupId>
    	<artifactId>java-jwt</artifactId>
    	<version>3.2.0</version>
    </dependency>
    <dependency>
    	<groupId>io.jsonwebtoken</groupId>
    	<artifactId>jjwt</artifactId>
    	<version>0.7.0</version>
    </dependency>
    <!-- JWT需要另外添加的 -->
    <dependency>
    	<groupId>javax.xml.bind</groupId>
    	<artifactId>jaxb-api</artifactId>
    	<version>2.3.0</version>
    </dependency>
    <dependency>
    	<groupId>com.sun.xml.bind</groupId>
    	<artifactId>jaxb-impl</artifactId>
    	<version>2.3.0</version>
    </dependency>
    <dependency>
    	<groupId>com.sun.xml.bind</groupId>
    	<artifactId>jaxb-core</artifactId>
    	<version>2.3.0</version>
    </dependency>
    <dependency>
    	<groupId>javax.activation</groupId>
    	<artifactId>activation</artifactId>
    	<version>1.1.1</version>
    </dependency>
    

    JwiUtils.java

    package com.example.test_spring_boot_1.utils;
    
    import com.example.test_spring_boot_1.domain.User;
    import io.jsonwebtoken.*;
    import org.bouncycastle.util.encoders.Base64;
    
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;
    import java.util.Date;
    
    public class JwtUtils {
    
        /**
         * 主题
         */
        private static final String SUBJECT = "testJWT";
        /**
         * 生成秘钥的字符串
         */
        private static final String KEYSTRING = "keyItself";
    
        /**
         * 过期毫秒数
         */
        private static final long EXPIRE = 1000*60*60*24*7;
    
        /**
         * 生成秘钥的方法
         * @return
         */
        public static SecretKey generalKey(){
            byte[] encodedKey = Base64.decode(KEYSTRING); //base64编码的字符数组
            SecretKey key = new SecretKeySpec(encodedKey,0,encodedKey.length,"AES"); //加密
            return key;
        }
    
        /**
         * 签发jwt
         * @return
         */
        public static String createJWT(User user){
            //加密算法
            SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
            //当前时间毫秒数
            long nowMillis = System.currentTimeMillis();
            Date now = new Date(nowMillis);
            Date expDate = new Date(nowMillis+EXPIRE);
            SecretKey secretKey = generalKey();
            JwtBuilder builder = Jwts.builder()
                    .setSubject(SUBJECT) //主题
                    .claim("name",user.getName()) //用K-V方式保存负载的Json数据
                    .setIssuedAt(now) //签发时间
                    .setExpiration(expDate) //过期时间
                    .signWith(signatureAlgorithm,secretKey); //签名算法及秘钥
            return builder.compact();
        }
    
        /**
         * 验证jwt
         * @param jwtStr
         */
        public static Claims checkJWT(String jwtStr) throws JwtException {
            SecretKey key = generalKey();
            try{
                final Claims claims= Jwts.parser()
                        .setSigningKey(key) //设置秘钥
                        .parseClaimsJws(jwtStr) //指定要解密的字符串
                        .getBody(); //获取负载的内容
                return claims;
            }catch (JwtException ex){
                System.out.println("token验证失败");
            }
            return null;
        }
    }
    
    

    CommonText.java

    package com.example.test_spring_boot_1;
    
    
    import com.example.test_spring_boot_1.domain.User;
    import com.example.test_spring_boot_1.utils.JwtUtils;
    import io.jsonwebtoken.Claims;
    import org.junit.Test;
    
    public class CommonText {
        @Test
        public void testGeneJwt(){
            User user = new User();
            user.setId(999);
            user.setHeadImg("www.xdclass.net");
            user.setName("xd");
    
            String token = JwtUtils.createJWT(user);
            System.out.println(token);
        }
    
        @Test
        public void testToken(){
            String token = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0SldUIiwibmFtZSI6InhkIiwiaWF0IjoxNTY1MDMwMDIzLCJleHAiOjE1NjU2MzQ4MjN9.y2SuulgO88tE-Ets7PkIyiIQF1WjAmai7sVDdkgaAf0";
            Claims claims = JwtUtils.checkJWT(token);
            if(claims != null){
                String name = (String)claims.get("name");
                System.out.println(name);
            }
        }
    }
    
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值