分布式session解决方案 — — JWT(生成token)

JWT 跨域认证解决方案

1 介绍

  • JWT(JSON Web Token)是目前最流行的跨域认证解决方案,是一种基于Token的认证授权机制,JWT本身也是Token,是一种规范化之后的JSON结构的Token。
  • JWT自身包含了验证所需要的所有信息,因此,我们的服务器不需要存储Session信息(其他解决方案:hash、session共享),增加了系统的可用性和伸缩性,大大减轻了服务端的压力。
  • JWT更符合RESTFul API的无状态原则
  • JWT认证可以有效避免CSRF(跨站请求伪造攻击),因为JWT一般是存在在localStorage中,使用JWT进行身份验证的过程中不会涉及到Cookie

2 组成部分

JWT本质就是一组字符串,通过(.)切分成三个为Base64编码的部分:

  1. Header:描述JWT元数据,定义生成签名的算法及Token类型
  2. Payload:存放实际要传递的数据
  3. Signature(签名):服务器通过Payload、Header和一个密钥(Secret)使用Header里面指定的签名算法(默认是HMAC SHA256)

实例:用点分割,分为三部分
在这里插入图片描述

3 JWT工具类的编写(企业开发)

3.1 定义对应编码及盐值(加密时)

//定义对应的编码算法
static SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
//盐值,盐值随意,看公司要求【此处我采用UUID】
static String secretKey = "d8de020f63754a9fa746ea74b831afc3";

3.2 获取key

//获取key(指定算法和盐值的key对象)
private static Key generateKey(){
    //将盐值转成字节
    byte[] bytes = DatatypeConverter.parseBase64Binary(secretKey);
    //根据算法和盐值生成对应的key值
    Key key = new SecretKeySpec(bytes, signatureAlgorithm.getJcaName());
    return key;
}

3.3 生成token(generatorToken)

/**
 * 将我们的数据使用JWT的方式变成一个token xxx.yyy.zzz
 * @param payLoad   负载(数据信息)
 * @return
 */
public static String generatorToken(Map<String, String> payLoad){
    ObjectMapper objectMapper = new ObjectMapper();
    try{
        //构建jwt生成器
        JwtBuilder builder = Jwts.builder();
        //将负载信息设置到jwt生成器中
        JwtBuilder jwtBuilder = builder.setPayload(objectMapper.writeValueAsString(payLoad));
        //根据签名算法和key值,生成新的jwtBuilder
        JwtBuilder jwtBuilder1 = jwtBuilder.signWith(signatureAlgorithm, generateKey());
        String token = jwtBuilder1.compact();
        return token;
    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }
    return null;
}

3.4 获取token中的body信息

/**
  * 根据指定的token, 返回对应的body信息
  * @param token
  * @return
  */
 public static Claims phaseTokenGetBody(String token){
     JwtParser jwtParser = Jwts.parser().setSigningKey(generateKey());
     Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);
     Claims body = claimsJws.getBody();//主要存放的信息
     return body;
 }

3.5 获取token中的signature信息

/**
  * 根据指定的token获取签名信息
  * @param token
  * @return
  */
 public static String phaseTokenGetSignature(String token){
     JwtParser jwtParser = Jwts.parser().setSigningKey(generateKey());
     Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);
     String signature = claimsJws.getSignature();
     return signature;
 }

3.6 获取token中的头信息

/**
 * 根据指定的token获取头信息
 * @param token
 * @return
 */
public static JwsHeader phaseTokenGetHeader(String token){
    //获取解析器
    JwtParser parser = Jwts.parser();
    //设置签名key(盐值)
    parser = parser.setSigningKey(generateKey());
    //解析token
    Jws<Claims> claimsJws = parser.parseClaimsJws(token);
    JwsHeader header = claimsJws.getHeader();
    return header;
}

3.7 测试

①在map中存入自己的数据,调用自定义API生成对应token

public static void main(String[] args) {
    //随机获取盐值
//        System.out.println(UUID.randomUUID().toString().replaceAll("-", ""));
    Map<String, String> payLoad = new HashMap<>();
    payLoad.put("name", "curry");
    String s = generatorToken(payLoad);
    //eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiY3VycnkifQ.Sf3GiF3p56nLzoAxEHLXcAckPmmPTtecj1_lGT9oV8s
    System.out.println(s);
}

②在jwt官网https://jwt.io/中进行解析,也可以调用自己的API进行解析
在这里插入图片描述
调用自己API:

//调用自定义API获取结果
Claims claims = phaseTokenGetBody(s);
//{name=curry}

③如果所给token有误,则会报错

Exception in thread "main" io.jsonwebtoken.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.

4 全部代码包含测试

package com.zi.api.commons.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.*;

import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.HashMap;
import java.util.Map;

/**
 * 生成jwt工具类
 */
public class JJWTRootUtils {

    //定义对应的编码算法
    static SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
    //盐值
    static String secretKey = "d8de020f63754a9fa746ea74b831afc3";

    //获取key(指定算法和盐值的key对象)
    private static Key generateKey(){
        //将盐值转成字节
        byte[] bytes = DatatypeConverter.parseBase64Binary(secretKey);
        //根据算法和盐值生成对应的key值
        Key key = new SecretKeySpec(bytes, signatureAlgorithm.getJcaName());
        return key;
    }

    /**
     * 将我们的数据使用JWT的方式变成一个token xxx.yyy.zzz
     * @param payLoad   负载(数据信息)
     * @return
     */
    public static String generatorToken(Map<String, String> payLoad){
        ObjectMapper objectMapper = new ObjectMapper();
        try{
            //构建jwt生成器
            JwtBuilder builder = Jwts.builder();
            //将负载信息设置到jwt生成器中
            JwtBuilder jwtBuilder = builder.setPayload(objectMapper.writeValueAsString(payLoad));
            //根据签名算法和key值,生成新的jwtBuilder
            JwtBuilder jwtBuilder1 = jwtBuilder.signWith(signatureAlgorithm, generateKey());
            String token = jwtBuilder1.compact();
            return token;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据指定的token, 返回对应的body信息
     * @param token
     * @return
     */
    public static Claims phaseTokenGetBody(String token){
        JwtParser jwtParser = Jwts.parser().setSigningKey(generateKey());
        Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);
        Claims body = claimsJws.getBody();//主要存放的信息
        return body;
    }

    /**
     * 根据指定的token获取签名信息
     * @param token
     * @return
     */
    public static String phaseTokenGetSignature(String token){
        JwtParser jwtParser = Jwts.parser().setSigningKey(generateKey());
        Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);
        String signature = claimsJws.getSignature();
        return signature;
    }


    /**
     * 根据指定的token获取头信息
     * @param token
     * @return
     */
    public static JwsHeader phaseTokenGetHeader(String token){
        //获取解析器
        JwtParser parser = Jwts.parser();
        //设置签名key(盐值)
        parser = parser.setSigningKey(generateKey());
        //解析token
        Jws<Claims> claimsJws = parser.parseClaimsJws(token);
        JwsHeader header = claimsJws.getHeader();
        return header;
    }


    public static void main(String[] args) {
        //随机获取盐值
//        System.out.println(UUID.randomUUID().toString().replaceAll("-", ""));
        Map<String, String> payLoad = new HashMap<>();
        payLoad.put("name", "curry");
        String s = generatorToken(payLoad);
        //eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiY3VycnkifQ.Sf3GiF3p56nLzoAxEHLXcAckPmmPTtecj1_lGT9oV8s
        System.out.println(s);

        //调用自定义API获取结果
        Claims claims = phaseTokenGetBody(s);
        //{name=curry}
        System.out.println(claims);
    }

}


版权声明:本文为weixin_45565886原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。