当前位置:   article > 正文

JWT基础介绍

jwt

1.无状态登录原理

1.1.什么是有状态?

有状态服务,即服务端需要记录每次会话的客户端信息,从而识别客户端身份,根据用户身份进行请求的处理,典型的设计如tomcat中的session。

例如登录:用户登录后,我们把登录者的信息保存在服务端session中,并且给用户一个cookie值,记录对应的session。然后下次请求,用户携带cookie值来,我们就能识别到对应session,从而找到用户的信息。

缺点是什么?

  • 服务端保存大量数据,增加服务端压力
  • 服务端保存用户状态,无法进行水平扩展
  • 客户端请求依赖服务端,多次请求必须访问同一台服务器

1.2.什么是无状态

微服务集群中的每个服务,对外提供的都是Rest风格的接口。而Rest风格的一个最重要的规范就是:服务的无状态性,即:

  • 服务端不保存任何客户端请求者信息
  • 客户端的每次请求必须具备自描述信息,通过这些信息识别客户端身份

带来的好处是什么呢?

  • 客户端请求不依赖服务端的信息,任何多次请求不需要必须访问到同一台服务
  • 服务端的集群和状态对客户端透明
  • 服务端可以任意的迁移和伸缩
  • 减小服务端存储压力

1.3.如何实现无状态

无状态登录的流程:

  • 当客户端第一次请求服务时,服务端对用户进行信息认证(登录)
  • 认证通过,将用户信息进行加密形成token,返回给客户端,作为登录凭证
  • 以后每次请求,客户端都携带认证的token
  • 服务端对token进行解密,判断是否有效。

流程图:

在这里插入图片描述

整个登录过程中,最关键的点是什么?

token的安全性

token是识别客户端身份的唯一标示,如果加密不够严密,被人伪造那就完蛋了。

采用何种方式加密才是安全可靠的呢?

我们将采用JWT + RSA非对称加密

1.4.JWT

1.4.1.简介

JWT,全称是Json Web Token, 是JSON风格轻量级的授权和身份认证规范,可实现无状态、分布式的Web应用授权;官网:https://jwt.io

在这里插入图片描述

GitHub上jwt的java客户端:https://github.com/jwtk/jjwt

1.4.2.数据格式

JWT包含三部分数据:

  • Header:头部,通常头部有两部分内容:

    • 声明类型,这里是JWT
    • 签名算法,自定义

    我们会对头部进行base64加密(可解密),得到第一部分数据

  • Payload:载荷,就是有效数据,一般包含下面信息:

    • 用户身份信息(注意,这里因为采用base64加密,可解密,因此不要存放敏感信息
    • tokenID:当前这个JWT的唯一标示
    • 注册声明:如token的签发时间,过期时间,签发人等

    这部分也会采用base64加密,得到第二部分数据

  • Signature:签名,是整个数据的认证信息。一般根据前两步的数据,再加上服务的的密钥(secret)(不要泄漏,最好周期性更换),通过加密算法生成。用于验证整个数据完整和可靠性

生成的数据格式:

在这里插入图片描述

可以看到分为3段,每段就是上面的一部分数据

1.4.3.JWT交互流程

流程图:

在这里插入图片描述

  • 授权流程:
    • 1、用户请求登录,携带用户名密码到授权中心
    • 2、授权中心携带用户名密码,到用户中心查询用户
    • 3、查询如果正确,生成JWT凭证
    • 4、返回JWT给用户
  • 鉴权流程:
    • 1、用户请求某微服务功能,携带JWT
    • 2、微服务将jwt交给授权中心校验
    • 3、授权中心返回校验结果到微服务
    • 4、微服务判断校验结果,成功或失败
    • 5、失败则直接返回401
    • 6、成功则处理业务并返回

因为JWT签发的token中已经包含了用户的身份信息,并且每次请求都会携带,这样服务的就无需保存用户信息,甚至无需去数据库查询,完全符合了Rest的无状态规范。

不过,这个过程是不是就完美了呢?

可以发现,用户访问我们的网站,一次授权后,以后访问微服务都需要鉴权,那么每次鉴权都需要访问授权中心,一个用户请求,被分解为2次请求才能完成,效率比较低。

能不能直接在微服务的完成鉴权,不去找授权中心呢?

如果这样,就可以减少一次网络请求,效率提高了一倍。但是,微服务并没有鉴定JWT的能力,因为鉴定需要通过密钥来完成。我们不能把密钥交给其它微服务,存在安全风险。

怎么办?

这就要用到RSA非对称加密技术了。

1.5.非对称加密验签

1.5.1.加密技术的类型

加密技术是对信息进行编码和解码的技术,编码是把原来可读信息(又称明文)译成代码形式(又称密文),其逆过程就是解码(解密),加密技术的要点是加密算法,加密算法可以分为三类:

  • 对称加密,如AES
    • 基本原理:将明文分成N个组,然后使用密钥对各个组进行加密,形成各自的密文,最后把所有的分组密文进行合并,形成最终的密文。
    • 优势:算法公开、计算量小、加密速度快、加密效率高
    • 缺陷:双方都使用同样密钥,安全性得不到保证
  • 非对称加密,如RSA
    • 基本原理:同时生成两把密钥:私钥和公钥,私钥隐秘保存公钥可以下发给信任客户端
      • 私钥加密,持有私钥或公钥才可以解密
      • 公钥加密,持有私钥才可解密
    • 优点:安全,难以破解
    • 缺点:算法比较耗时
  • 不可逆加密,如MD5,SHA
    • 基本原理:加密过程中不需要使用密钥,输入明文后由系统直接经过加密算法处理成密文,这种加密后的数据是无法被解密的,无法根据密文推算出明文。

RSA算法历史:

1977年,三位数学家Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密。这种算法用他们三个人的名字缩写:RSA

1.5.2.非对称加密验签

有了非对称加密,我们就可以改变签名和验签的方式了:

  • 生成RSA密钥对,私钥存放在授权中心,公钥下发给微服务

  • 在授权中心利用私钥对JWT签名

  • 在微服务利用公钥验证签名有效性

因为非对称加密的特性,不用担心公钥泄漏问题,因为公钥是无法伪造签名的,但要确保私钥的安全和隐秘

非对称加密后的授权和鉴权流程:

在这里插入图片描述

鉴权部分简化了非常多:

在这里插入图片描述

用户只需要与微服务交互,不用访问授权中心,效率大大提高!

2.编写工具

2.1 JWT工具类

/**
 * <!--日期工具类-->
 * <dependency>
 * <groupId>joda-time</groupId>
 * <artifactId>joda-time</artifactId>
 * </dependency>
 * <p>
 * <!--JWT依赖-->
 * <dependency>
 * <groupId>io.jsonwebtoken</groupId>
 * <artifactId>jjwt-api</artifactId>
 * <version>0.10.5</version>
 * </dependency>
 * <dependency>
 * <groupId>io.jsonwebtoken</groupId>
 * <artifactId>jjwt-impl</artifactId>
 * <version>0.10.5</version>
 * <scope>runtime</scope>
 * </dependency>
 * <dependency>
 * <groupId>io.jsonwebtoken</groupId>
 * <artifactId>jjwt-jackson</artifactId>
 * <version>0.10.5</version>
 * <scope>runtime</scope>
 * </dependency>
 */


package com.xlCai.ctx.bean;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.joda.time.DateTime;
import org.springframework.util.StringUtils;

import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;

public class JwtUtils {

    private static final String JWT_PAYLOAD_USER_KEY = "user";


    private static final String SUBJECT = "ABCDEFG";

    private static final String APPSECRET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz";

    private static final String CLAIMOBJKEY = "CLAIMOBJKEY";


    /**
     * 分钟 如果要改天或者其他自己改
     * 生成token,只使用jwt不使用RSA
     *
     * @return
     */
    public static String generateTokenExpireInMinutesOnlyByJwt(String obj, int expireMinutes) {

        if (StringUtils.isEmpty(obj)) {
            return null;
        }
        return Jwts.builder().setSubject(SUBJECT)
                .claim(CLAIMOBJKEY, obj)
                .setIssuedAt(new Date())
                .setExpiration(DateTime.now().plusMinutes(expireMinutes).toDate())
                .signWith(SignatureAlgorithm.HS256, APPSECRET)
                .compact();
    }


    /**
     * 解析token
     *
     * @param token 成Claims
     * @return
     */
    public static Claims parserTokenOnlyByJwt(String token) {

        return Jwts.parser().setSigningKey(APPSECRET).parseClaimsJws(token).getBody();

    }

    /**
     * 解析token
     *
     * @param token 成对象
     * @return
     */
    public static <T> Object parserObjectFromTokenOnlyByJwt(String token, Class<T> type) {

        Claims body = Jwts.parser().setSigningKey(APPSECRET).parseClaimsJws(token).getBody();
        return body.get(CLAIMOBJKEY);
    }


    /**
     * 私钥加密token
     *
     * @param info          载荷中的数据
     * @param privateKey    私钥
     * @param expireMinutes 过期时间,单位分钟
     * @return JWT
     */
    public static String generateTokenExpireInMinutes(Object info, PrivateKey privateKey, int expireMinutes) {
        return Jwts.builder()
                .claim(JWT_PAYLOAD_USER_KEY, JsonUtils.toString(info))
                .setId(createJTI())
                .setIssuedAt(new Date())
                .setExpiration(DateTime.now().plusMinutes(expireMinutes).toDate())
                .signWith(privateKey, SignatureAlgorithm.RS256)
                .compact();
    }

    /**
     * 私钥加密token
     *
     * @param Info          载荷中的数据
     * @param privateKey    私钥
     * @param expireSeconds 过期时间,单位秒
     * @return JWT
     */
    public static String generateTokenExpireInSeconds(Object Info, PrivateKey privateKey, int expireSeconds) {
        return Jwts.builder()
                .claim(JWT_PAYLOAD_USER_KEY, JsonUtils.toString(Info))
                .setId(createJTI())
                .setIssuedAt(new Date())
                .setExpiration(DateTime.now().plusSeconds(expireSeconds).toDate())
                .signWith(privateKey, SignatureAlgorithm.RS256)
                .compact();
    }

    /**
     * 公钥解析token
     *
     * @param token     用户请求中的token
     * @param publicKey 公钥
     * @return Jws<Claims>
     */
    private static Jws<Claims> parserToken(String token, PublicKey publicKey) {
        return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);
    }


    /**
     * 随机生成Id
     *
     * @return
     */
    private static String createJTI() {
        return new String(Base64.getEncoder().encode(UUID.randomUUID().toString().getBytes()));
    }

    /**
     * 获取token中的用户信息
     *
     * @param token     用户请求中的令牌
     * @param publicKey 公钥
     * @return 用户信息
     */
    public static <T> Payload<T> getInfoFromToken(String token, PublicKey publicKey, Class<T> type) {
        Jws<Claims> claimsJws = parserToken(token, publicKey);
        Claims body = claimsJws.getBody();
        Payload<T> payload = new Payload<>();
        payload.setId(body.getId());
        payload.setInfo(JsonUtils.toBean(body.get(JWT_PAYLOAD_USER_KEY).toString(), type));
        payload.setExpiration(body.getExpiration());
        return payload;
    }

    /**
     * 获取token中的载荷信息
     *
     * @param token     用户请求中的令牌
     * @param publicKey 公钥
     * @return 用户信息
     */
    public static <T> Payload<T> getInfoFromToken(String token, PublicKey publicKey) {
        Jws<Claims> claimsJws = parserToken(token, publicKey);
        Claims body = claimsJws.getBody();
        Payload<T> payload = new Payload<>();
        payload.setId(body.getId());
        payload.setExpiration(body.getExpiration());
        return payload;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190

2.2 载荷对象

package cn.juan.auth.entity;

import lombok.Data;

import java.util.Date;


/**
 * 载荷对象:
 * <p>
 * JWT中,会保存载荷数据,我们计划存储3部分:
 * <p>
 * - id:jwt的id
 * - 用户信息:用户数据,不确定,可以是任意类型
 * - 过期时间:Date
 *
 * @param <T>
 */
@Data
public class Payload<T> {
    private String id; //tokenId
    private T info; //实际存放内容
    private Date expiration; //过期时间
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

2.3 RSA工具类

package springcloud.dataencode;

import com.alibaba.fastjson.JSON;
import com.sun.istack.internal.logging.Logger;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;


/**
 * @version V1.0.0
 * @author: WangQingLong
 * @date: 2020/10/16 18:38
 * @description:
 *
 *         <dependency>
 *             <groupId>com.alibaba</groupId>
 *             <artifactId>fastjson</artifactId>
 *             <version>1.2.47</version>
 *         </dependency>
 *
 *         <!--RSA加密需要的依赖-->
 *         <dependency>
 *             <groupId>org.bouncycastle</groupId>
 *             <artifactId>bcprov-jdk15on</artifactId>
 *             <version>1.51</version>
 *         </dependency>
 *
 切记:  生成两对,可以使用枚举保存,公钥加密私钥解密,交叉进行
 
 *
 */
public final class RsaKit {
    private static Logger logger = Logger.getLogger(RsaKit.class);
    private static final int KEY_SIZE = 2048;

    //加密算法
    private static final String KEY_ALGORITHM = "RSA";
    //签名算法
    private static final String signature_algorithm = "MD5withRSA";

    private static final Charset charset = Charset.forName("UTF-8");

    private RsaKit() {
    }


    /**
     * 生成密钥对,生成的密钥对统一放在SystemConstant ,RsA_keyPair里一份
     *
     * @return
     */
    public static KeyPair generateKeyPair() {

        try {
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM, new BouncyCastleProvider());
            keyPairGen.initialize(KEY_SIZE, new SecureRandom());
            KeyPair keyPair = keyPairGen.generateKeyPair();
            return keyPair;
        } catch (Exception e) {
            logger.info("生成密钥对出现异常");
            throw new RuntimeException();
        }
    }

    /**
     * 获取私钥
     *
     * @param key
     * @return
     */
    public static String getPrivateKey(PrivateKey key) {
        return Base64.getEncoder().encodeToString(key.getEncoded());
    }


    /**
     * 获取公钥
     *
     * @param key
     * @return
     */
    public static String getPublickey(PublicKey key) {
        return Base64.getEncoder().encodeToString(key.getEncoded());
    }


    /**
     * 用私钥对信息生成数字签名
     *
     * @param data       已加密数据
     * @param privatekey 私钥
     * @param charset    编码
     * @return
     */
    public static String sign(String data, String privatekey, Charset charset) {
        byte[] dataBytes = data.getBytes(charset);
        return sign(dataBytes, privatekey);
    }


    /**
     * 用私钥对信息生成数字签名
     *
     * @param data       已加密数据
     * @param privatekey 密钥
     * @return
     */
    public static String sign(byte[] data, String privatekey) {
        try {
            byte[] keyBytes = Base64.getDecoder().decode(privatekey);
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
            Signature signature = Signature.getInstance(signature_algorithm);
            signature.initSign(privateKey);
            signature.update(data);
            return Base64.getUrlEncoder().encodeToString(signature.sign());
        } catch (Exception e) {
            logger.info("用私钥对信息生成数字签名出现异常");
            e.printStackTrace();
        }
        return null;
    }


    /**
     * @param data      数据
     * @param publickey 公钥
     * @param sign      数据签名
     * @return
     */
    public static boolean verify(byte[] data, String publickey, String sign) {
        try {
            byte[] keyBytes = Base64.getDecoder().decode(publickey);

            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);

            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

            PublicKey publicKey = keyFactory.generatePublic(keySpec);

            Signature signature = Signature.getInstance(signature_algorithm);
            signature.initVerify(publicKey);
            signature.update(data);
            return signature.verify(Base64.getUrlDecoder().decode(sign));
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;

    }


    /**
     * @param data      数据
     * @param publickey 公钥
     * @param sign      签名
     * @param charset   编码
     * @return
     */
    public static boolean verify(String data, String publickey, String sign, Charset charset) {
        try {
            byte[] keyBytes = Base64.getDecoder().decode(publickey);

            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);

            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

            PublicKey publicKey = keyFactory.generatePublic(keySpec);

            Signature signature = Signature.getInstance(signature_algorithm);
            signature.initVerify(publicKey);
            signature.update(data.getBytes(charset));
            return signature.verify(Base64.getUrlDecoder().decode(sign));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }


    /**
     * 校验数字签名
     *
     * @param data      数据
     * @param publickey 公钥
     * @param sign      签名
     * @return
     */
    public static boolean verify(String data, String publickey, String sign) {
        return verify(data, publickey, sign, charset);
    }

    /**
     * 私钥解密
     *
     * @param encrypteData 已加密数据
     * @param privatekey   私钥
     * @return
     */
    public static byte[] decryptByPrivatekey(byte[] encrypteData, String privatekey) {
        try {
            byte[] keyBytes = Base64.getDecoder().decode(privatekey);
            PKCS8EncodedKeySpec pkcs8keySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM, new BouncyCastleProvider());
            RSAPrivateKey privateK = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8keySpec);
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, privateK);
            int inputLen = encrypteData.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offset = 0;
            byte[] cache;
            int i = 0;
            int MAX_DECRYPT_BLOCK = privateK.getModulus().bitLength() / 8;
            //读数据进行分段解密
            while (inputLen - offset > 0) {
                if (inputLen - offset > MAX_DECRYPT_BLOCK) {
                    cache = cipher.doFinal(encrypteData, offset, MAX_DECRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(encrypteData, offset, inputLen - offset);
                }
                out.write(cache, 0, cache.length);
                i++;
                offset = i * MAX_DECRYPT_BLOCK;
            }
            byte[] decrypteData = out.toByteArray();
            out.close();
            return decrypteData;
        } catch (Exception e) {
            logger.info("私钥解密出现异常");
            e.printStackTrace();
        }

        return null;
    }


    /**
     * 私钥解密
     *
     * @param encryptedData 已加密数据
     * @param privatekey    私钥
     * @param charset       编码
     * @return
     */
    public static String decryptByPrivatekey(String encryptedData, String privatekey, Charset charset) {

        try {
            byte[] bytes = RsaKit.decryptByPrivatekey(Base64.getUrlDecoder().decode(encryptedData), privatekey);
            return new String(bytes, charset);
        } catch (Exception e) {
            logger.info("私钥解密出现异常");
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 公钥解密
     *
     * @param encryteData 加密数据
     * @param publickey   公钥加密
     * @return
     */
    public static byte[] decryptByPublickey(byte[] encryteData, String publickey) {
        try {
            byte[] keyBytes = Base64.getDecoder().decode(publickey);
            X509EncodedKeySpec x509keySpec = new X509EncodedKeySpec(keyBytes);

            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM, new BouncyCastleProvider());
            RSAPublicKey publicK = (RSAPublicKey) keyFactory.generatePublic(x509keySpec);

            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

            cipher.init(Cipher.DECRYPT_MODE, publicK);
            int inputLen = encryteData.length;

            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offset = 0;
            byte[] cache;
            int i = 0;
            int max_decrypt_block = publicK.getModulus().bitLength() / 8;
            //对数据分段解密
            while (inputLen - offset > 0) {
                if (inputLen - offset > max_decrypt_block) {
                    cache = cipher.doFinal(encryteData, offset, max_decrypt_block);
                } else {
                    cache = cipher.doFinal(encryteData, offset, inputLen - offset);
                }
                out.write(cache, 0, cache.length);
                i++;
                offset = i * max_decrypt_block;
            }
            byte[] decryptedData = out.toByteArray();
            out.close();
            return decryptedData;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }


    /**
     * 公钥解密
     *
     * @param encryptedData 加密数据
     * @param publicKey     公钥
     * @param Charset       编码
     * @return
     */
    public static String decryptByPublicKey(String encryptedData, String publicKey, String Charset) {
        try {
            byte[] bytes = RsaKit.decryptByPublickey(Base64.getUrlDecoder().decode(encryptedData), publicKey);
            return new String(bytes, charset);
        } catch (Exception e) {
            logger.info("公钥解密出现异常");
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 公钥加密
     *
     * @param data      数据
     * @param publicKey 公钥
     * @return
     */
    public static byte[] encryptByPublicKey(byte[] data, String publicKey) {
        try {
            byte[] keyBytes = Base64.getDecoder().decode(publicKey);

            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM, new BouncyCastleProvider());

            RSAPublicKey publicK = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);

            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, publicK);
            int inputLen = data.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offset = 0;
            byte[] cache;
            int i = 0;
            int max_encrypt_block = publicK.getModulus().bitLength() / 8 - 11;
            while (inputLen - offset > 0) {
                if (inputLen - offset > max_encrypt_block) {
                    cache = cipher.doFinal(data, offset, max_encrypt_block);
                } else {
                    cache = cipher.doFinal(data, offset, inputLen - offset);
                }
                out.write(cache, 0, cache.length);
                i++;
                offset = i * max_encrypt_block;
            }
            byte[] encrypteData = out.toByteArray();
            out.close();
            return encrypteData;

        } catch (Exception e) {
            logger.info("公钥加密出现异常");
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 公钥加密
     *
     * @param data      数据
     * @param publicKey 公钥
     * @param charset   编码
     * @return
     */
    public static String encryptByPublicKey(String data, String publicKey, Charset charset) {
        try {
            byte[] dataBytes = data.getBytes(charset);
            byte[] encrypt = encryptByPublicKey(dataBytes, publicKey);
            return Base64.getUrlEncoder().encodeToString(encrypt);
        } catch (Exception e) {
            logger.info("公钥加密出现异常");
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 私钥加密
     *
     * @param data
     * @param privateKey
     * @return
     */
    public static byte[] encryptByPrivateKey(byte[] data, String privateKey) {

        try {
            byte[] keyBytes = Base64.getDecoder().decode(privateKey);

            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM, new BouncyCastleProvider());

            RSAPrivateKey privateK = (RSAPrivateKey) keyFactory.generatePublic(x509KeySpec);

            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, privateK);
            int inputLen = data.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offset = 0;
            byte[] cache;
            int i = 0;
            int max_encrypt_block = privateK.getModulus().bitLength() / 8 - 11;
            while (inputLen - offset > 0) {
                if (inputLen - offset > max_encrypt_block) {
                    cache = cipher.doFinal(data, offset, max_encrypt_block);
                } else {
                    cache = cipher.doFinal(data, offset, inputLen - offset);
                }
                out.write(cache, 0, cache.length);
                i++;
                offset = i * max_encrypt_block;
            }
            byte[] encrypteData = out.toByteArray();
            out.close();
            return encrypteData;

        } catch (Exception e) {
            logger.info("私钥加密出现异常");
            e.printStackTrace();
        }
        return null;
    }

    public static String encryptByPrivateKey(String data, String privateKey, Charset charset) {
        try {
            byte[] dataBytes = data.getBytes(charset);
            byte[] encrypt = encryptByPublicKey(dataBytes, privateKey);
            return Base64.getUrlEncoder().encodeToString(encrypt);
        } catch (Exception e) {
            logger.info("私钥加密出现异常");
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        KeyPair keyPair = generateKeyPair();
        PublicKey aPublic = keyPair.getPublic();
        String publickey = getPublickey(aPublic);
        System.out.println("publickey = " + publickey);

        PrivateKey aPrivate = keyPair.getPrivate();
        String privateKey = getPrivateKey(aPrivate);
        System.out.println("privateKey = " + privateKey);

        HashMap<Object, Object> map = new HashMap<>();
        map.put("张三", "李四");
        String s = JSON.toJSONString(map);

        String s1 = encryptByPublicKey(s, publickey, charset);
        System.out.println("加密数据为:"+s1);
        String s2 = decryptByPrivatekey(s1, privateKey, charset);
        System.out.println("解密之后数据为:"+s2);
        Map map1 = JSON.parseObject(s2, Map.class);
        System.out.println("map1 = " + map1);

    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/932632
推荐阅读
相关标签
  

闽ICP备14008679号