Bootstrap

JWT,这一篇就够了

目录

1.Cookie、session、token的区别与联系

2.传统的Session认证

3.基于JWT认证

 4.JWT的结构

标头

有效载荷

签名

 第一个JWT程序

常见的异常信息

 JWTUtils工具类(直接使用)


1.Cookie、session、token的区别与联系

  • 由于HTTP是无状态协议,客户端每次访问服务端,服务端不会保留客户端的信息,即上一次请求对这一次请求没有任何影响。
  • Cookie:浏览器向服务器发送请求,服务器会set-cookie设置Cookie的值(key,value),服务器发送给浏览器,浏览器保存Cookie的值,之后客户端每次访问浏览器,都会带上这个Cookie值,打开浏览器可以查看保存了哪些Cookie的值。(不安全)
  • Session:浏览器向服务器发送请求,服务器验证用户名和密码是对的,会创建一个SessionId和会话结束时间,然后将SessionId放入Cookie中,会话结束时间就是Cookie的有效期。之后每次访问都会携带带有SessionId的Cookie值,直到有效期结束,就需要再次输入用户名和密码
  • 随着用户体积的增大,服务器端需要保存大量的Session,对内存的消耗大。如果搭建的是分布式集群项目,又存在Session共享的问题。因此推出了JWT
  • JWT:生成于服务端,保存于客户端。

2.传统的Session认证

3.基于JWT认证

 4.JWT的结构

  • 标头(header)
  • 有效载荷(payload)
  • 签名(signature)

标头

包含两个部分:令牌的类型和所使用的签名算法.标头使用的是Base64编码,注意Base64编码不是一种加密的过程,可以被解码为初始值。

{
"typ":"JWT",
"alg":"HS256"
}

有效载荷

有效载荷存放的是用户的数据信息,通过Base64进行加密,不要在Payload中存放重要的值。

签名

签名是将编码后的(标头、有效载荷和我们提供的一个密钥)和我们Header中指定的签名算法进行编码。

比如客户端传入  Header(A)、Payload(B)、Signature(C),我们需要通过A、B和密钥通过Base64编码后的值和C进行对比,如果值相同则正确。

 第一个JWT程序

    @Test
    void contextLoads() {
        Map<String, Object> map = new HashMap<String,Object>();
        map.put("typ","JWT");
        map.put("alg","HS256");
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.SECOND,50);
        String token= JWT.create()
                .withHeader(map)
                .withClaim("username", "lele")
                .withClaim("age", 17)
                .withExpiresAt(instance.getTime())
                .sign(Algorithm.HMAC256("uadisjdlkas**&&^&"));
        System.out.println(token);
    }
    @Test
    void jiemi(){
        //获取到签名
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("uadisjdlkas**&&^&")).build();
        //进行验证
        DecodedJWT verify = jwtVerifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NTkxNTQyNjMsImFnZSI6MTcsInVzZXJuYW1lIjoibGVsZSJ9.SVjXtp35e3AioWzk7TADKDeGGWTSHOmtJ2pGLCBoiuc");
        //允许放多个
        //得到
        System.out.println(verify.getClaim("username").asString());
        System.out.println(verify.getClaim("age").asInt());
        System.out.println(verify.getExpiresAt());

    }

常见的异常信息

 JWTUtils工具类(直接使用)

package com.lele.utils;


import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import io.jsonwebtoken.*;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.SecretKey;

/**
 * @author:Tlimited
 *
 */
public class JWTUtils {

    private static final long EXPIRE = 60 * 1000; //过期时间

    public   static final String key = "ajsdaklsdjalskdasj";//密钥,动态生成的密钥

    /**
     * 生成token
     *
     * @param claims 要传送消息map
     * @return
     */
    public static String generate(Map<String,Object> claims) {
        Date nowDate = new Date();
        //过期时间,设定为一分钟
        Date expireDate = new Date(System.currentTimeMillis() + EXPIRE);
        //头部信息,可有可无
        Map<String, Object> header = new HashMap<>(2);
        header.put("typ", "jwt");

        //更强的密钥,JDK11起才能用
        //  KeyPair keyPair = Keys.keyPairFor(SignatureAlgorithm.RS256);
        //  PrivateKey key1 =  keyPair.getPrivate();  // 私钥
        //PublicKey key2 =  keyPair.getPublic();  //公钥

        return Jwts.builder().setHeader(header)
                // .setSubject("weimi")//主题
                // .setIssuer("weimi") //发送方
                .setClaims(claims)  //自定义claims
                .setIssuedAt(nowDate)//当前时间
                .setExpiration(expireDate) //过期时间
                .signWith(SignatureAlgorithm.HS256,key)//签名算法和key
                .compact();
    }

    /**
     * 生成token
     * @param header  传入头部信息map
     * @param claims  要传送消息map
     * @return
     */
    public static String generate( Map<String, Object> header,Map<String,Object> claims) {
        Date nowDate = new Date();
        //过期时间,设定为一分钟
        Date expireDate = new Date(System.currentTimeMillis() + EXPIRE);
        return Jwts.builder().setHeader(header)
                // .setSubject("weimi")//主题
                //    .setIssuer("weimi") //发送方
                .setClaims(claims)  //自定义claims
                .setIssuedAt(nowDate)//当前时间
                .setExpiration(expireDate) //过期时间
                .signWith(SignatureAlgorithm.HS256,key)//签名算法和key
                .compact();
    }

    /**
     * 校验是不是jwt签名
     * @param token
     * @return
     */
    public static boolean isSigned(String token){
        return  Jwts.parser()
                .setSigningKey(key)
                .isSigned(token);
    }

    /**
     * 校验签名是否正确
     * @param token
     * @return
     */
    public static boolean verify(String token){
        try {
            Jwts.parser()
                    .setSigningKey(key)
                    .parseClaimsJws(token);
            return true;
        }catch (JwtException  e){
            System.out.println(e.getMessage());
            return false;
        }
    }

    /**
     * 获取payload 部分内容(即要传的信息)
     * 使用方法:如获取userId:getClaim(token).get("userId");
     * @param token
     * @return
     */
    public static Claims getClaim(String token) {
        Claims claims = null;
        try {
            claims = Jwts.parser()
                    .setSigningKey(key)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return claims;
    }

    /**
     * 获取头部信息map
     * 使用方法 : getHeader(token).get("alg");
     * @param token
     * @return
     */
    public static JwsHeader getHeader(String token) {
        JwsHeader header = null;
        try {
            header = Jwts.parser()
                    .setSigningKey(key)
                    .parseClaimsJws(token)
                    .getHeader();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return header;
    }

    /**
     * 获取jwt发布时间
     */
    public static Date getIssuedAt(String token) {
        return getClaim(token).getIssuedAt();
    }

    /**
     * 获取jwt失效时间
     */
    public static Date getExpiration(String token) {
        return getClaim(token).getExpiration();
    }

    /**
     * 验证token是否失效
     *
     * @param token
     * @return true:过期   false:没过期
     */
    public static boolean isExpired(String token) {
        try {
            final Date expiration = getExpiration(token);
            return expiration.before(new Date());
        } catch (ExpiredJwtException expiredJwtException) {
            return true;
        }
    }

    /**
     * 直接Base64解密获取header内容
     * @param token
     * @return
     */
    public static String getHeaderByBase64(String token){
        String header = null;
        if (isSigned(token)){
            try {
                byte[] header_byte = Base64.getDecoder().decode(token.split("\\.")[0]);
                header = new String(header_byte);
            }catch (Exception e){
                e.printStackTrace();
                return null;
            }
        }
        return header;
    }

    /**
     * 直接Base64解密获取payload内容
     * @param token
     * @return
     */
    public static String getPayloadByBase64(String token){
        String payload = null;
        if (isSigned(token)) {
            try {
                byte[] payload_byte = Base64.getDecoder().decode(token.split("\\.")[1]);
                payload = new String(payload_byte);
            }catch (Exception e){
                e.printStackTrace();
                return null;
            }
        }
        return payload;
    }

    public static void main(String[] args) {
        //用户自定义信息claims
        Map<String,Object> map = new HashMap<>();
        map.put("userId","test122");
        String token =  generate(map);
        System.out.println(token);

        System.out.println("claim:" + getClaim(token).get("userId"));
        System.out.println("header:" + getHeader(token));
        //    System.out.println(getIssuedAt(token));
        Claims claims=getClaim(token);

        //  System.out.println(getHeaderByBase64(token));
        System.out.println(getPayloadByBase64(token));
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy‐MM‐dd hh:mm:ss");
        System.out.println("签发时间:"+sdf.format(claims.getIssuedAt()));
        System.out.println("过期时间:"+sdf.format(claims.getExpiration()));
        System.out.println("当前时间:"+sdf.format(new Date()) );

    }
}

;