本文主要是介绍JWT Token生成与解析 + ECDSA加密技术,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
JWT Token生成与解析 + ECDSA加密技术
- 需要maven依赖
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency>
- 16进制字符串与byte数组互转工具类
/*** 16进制字符串与byte数组转换* @author chenyb**/
public final class HexUtil {private static final char[] HEX = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};public HexUtil() {}/*** byte数组转16进制字符串* @param bytes* @return*/public static String encodeHexString(byte[] bytes) {int nBytes = bytes.length;char[] result = new char[2 * nBytes];int j = 0;byte[] var4 = bytes;int var5 = bytes.length;for(int var6 = 0; var6 < var5; ++var6) {byte aByte = var4[var6];result[j++] = HEX[(240 & aByte) >>> 4];result[j++] = HEX[15 & aByte];}return new String(result);}/*** 16进制字符串转byte数组* @param s 字符串* @return*/public static byte[] decode(CharSequence s) {int nChars = s.length();if (nChars % 2 != 0) {throw new IllegalArgumentException("Hex-encoded string must have an even number of characters");} else {byte[] result = new byte[nChars / 2];for(int i = 0; i < nChars; i += 2) {int msb = Character.digit(s.charAt(i), 16);int lsb = Character.digit(s.charAt(i + 1), 16);if (msb < 0 || lsb < 0) {throw new IllegalArgumentException("Detected a Non-hex character at " + (i + 1) + " or " + (i + 2) + " position");}result[i / 2] = (byte)(msb << 4 | lsb);}return result;}}}
- 生成密钥对,校验密钥有效性
package com.jwt.ecdsa;import com.alibaba.fastjson.JSONObject;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;import javax.xml.bind.DatatypeConverter;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.text.SimpleDateFormat;
import java.util.Calendar;public class ECDSATest {/*** SIGNALGORITHMS* NONEwithECDSA 112-571 256 128 JDK/BC* RIPEMD160withECDSA 同上 256 160 BC* SHA1withECDSA ... 256 160 JDK/BC* SHA224withECDSA ... 256 224 BC* SHA256withECDSA ... 256 256 JDK/BC* SHA384withECDSA ... 256 384 JDK/BC* SHA512withECDSA ... 256 512 JDK/BC*/private static final String SIGNALGORITHMS = "SHA256withECDSA";private static final String ALGORITHM = "EC";private static final String SECP256K1 = "secp256k1";public static void main(String[] args) throws Exception {// 生成公钥私钥KeyPair keyPair1 = getKeyPair();PublicKey publicKey1 = keyPair1.getPublic();PrivateKey privateKey1 = keyPair1.getPrivate();//密钥转16进制字符串String publicKey = HexUtil.encodeHexString(publicKey1.getEncoded());String privateKey = HexUtil.encodeHexString(privateKey1.getEncoded());System.out.println("生成公钥:"+publicKey);System.out.println("生成私钥:"+privateKey);//16进制字符串转密钥对象PrivateKey privateKey2 = getPrivateKey(privateKey);PublicKey publicKey2 = getPublicKey(publicKey);//加签验签,设计自己的签名JSONObject o = new JSONObject();o.put( "id","sadasdsadsawq2132343243242ds" );o.put( "name","chenyb" );String data=o.toJSONString();String signECDSA = signECDSA(privateKey2, data);System.out.println(signECDSA);boolean verifyECDSA = verifyECDSA(publicKey2, signECDSA, data);System.out.println("验签结果:"+verifyECDSA);}/*** 加签* @param privateKey 私钥* @param data 数据* @return*/public static String signECDSA(PrivateKey privateKey, String data) {String result = "";try {//执行签名Signature signature = Signature.getInstance(SIGNALGORITHMS);signature.initSign(privateKey);signature.update(data.getBytes());byte[] sign = signature.sign();return HexUtil.encodeHexString(sign);} catch (Exception e) {e.printStackTrace();}return result;}/*** 验签* @param publicKey 公钥* @param signed 签名* @param data 数据* @return*/public static boolean verifyECDSA(PublicKey publicKey, String signed, String data) {try {//验证签名Signature signature = Signature.getInstance(SIGNALGORITHMS);signature.initVerify(publicKey);signature.update(data.getBytes());byte[] hex = HexUtil.decode(signed);boolean bool = signature.verify(hex);// System.out.println("验证:" + bool);return bool;} catch (Exception e) {e.printStackTrace();}return false;}/*** 从string转private key* @param key 私钥的字符串* @return* @throws Exception*/public static PrivateKey getPrivateKey(String key) throws Exception {byte[] bytes = DatatypeConverter.parseHexBinary(key);PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);return keyFactory.generatePrivate(keySpec);}/*** 从string转publicKey* @param key 公钥的字符串* @return* @throws Exception*/public static PublicKey getPublicKey(String key) throws Exception {byte[] bytes = DatatypeConverter.parseHexBinary(key);X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);return keyFactory.generatePublic(keySpec);}/*** 生成密钥对* @return* @throws Exception*/public static KeyPair getKeyPair() throws Exception {ECGenParameterSpec ecSpec = new ECGenParameterSpec(SECP256K1);KeyPairGenerator kf = KeyPairGenerator.getInstance(ALGORITHM);kf.initialize(ecSpec, new SecureRandom());KeyPair keyPair = kf.generateKeyPair();return keyPair;}}
- 测试密钥配对成功截图
- jwt生成token与解析
public static void main(String[] args) throws Exception {java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());//获取公钥私钥部分KeyPair keyPair1 = getKeyPair();PublicKey publicKey1 = keyPair1.getPublic();PrivateKey privateKey1 = keyPair1.getPrivate();//密钥转16进制字符串String publicKey = HexUtil.encodeHexString(publicKey1.getEncoded());String privateKey = HexUtil.encodeHexString(privateKey1.getEncoded());System.out.println("生成公钥:"+publicKey);System.out.println("生成私钥:"+privateKey);//16进制字符串转密钥对象PrivateKey privateKey2 = getPrivateKey(privateKey);PublicKey publicKey2 = getPublicKey(publicKey);//生成token部分SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Calendar c = Calendar.getInstance();c.add(Calendar.HOUR_OF_DAY, Integer.valueOf( 1000*60*5 ));//设置Token有效时长JSONObject o = new JSONObject();o.put("principal", "data数据");//封装数据Object类型o.put("exp", sdf.format(c.getTime()));//单纯的记录Token生成时间//SignatureAlgorithm.ES256 这里一定是对应的采用的加密技术String token = Jwts.builder().setClaims(o).setExpiration(c.getTime()).signWith( SignatureAlgorithm.ES256, privateKey2).compact();System.out.println("生成的token:"+token);//解析token部分final Claims claims = Jwts.parser().setSigningKey(publicKey2).parseClaimsJws(token).getBody();String str = (String) claims.get("principal");System.out.println("token解析出来的数据"+str);}
- 实战中,我们只需要提供生成token接口与解析token接口,将密钥对提前生成好存在文件里,在生成、与解析的时候调用就好
//接口部分
package com.jwt.service;public interface JwtService {String createToken(String str);String getData(String token);}//实现部分
package com.jwt.service.impl;import com.alibaba.fastjson.JSONObject;
import com.jwt.ecdsa.ECDSATest;
import com.jwt.service.JwtService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Service;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;/*** Created by chenyb .*/
@Service
public class JwtServiceImpl implements JwtService {@SuppressWarnings("restriction")private PublicKey getPublicKey() {PublicKey publicKey = null;try {InputStream stream = getClass().getClassLoader().getResourceAsStream("key/public.key");BufferedReader br = new BufferedReader(new InputStreamReader(stream));String line = "";StringBuffer sb = new StringBuffer();while ((line = br.readLine()) != null) {sb.append(line);}publicKey = ECDSATest.getPublicKey(sb.toString());} catch (Exception e) {e.printStackTrace();}return publicKey;}private PrivateKey getPrivateKey(){PrivateKey privateKey = null;try {InputStream stream = getClass().getClassLoader().getResourceAsStream("key/private.key");BufferedReader br = new BufferedReader(new InputStreamReader(stream));String line = "";StringBuffer sb = new StringBuffer();while ((line = br.readLine()) != null) {sb.append(line);}privateKey = ECDSATest.getPrivateKey( sb.toString() );} catch (Exception e) {e.printStackTrace();}return privateKey;}@Overridepublic String createToken(String str){java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());PrivateKey privateKey = this.getPrivateKey();JSONObject data = new JSONObject();data.put("data", str);SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Calendar c = Calendar.getInstance();c.add(Calendar.HOUR_OF_DAY, 1000*60*60*2);//token有效时间JSONObject o = new JSONObject();o.put("principal", data);o.put("exp", sdf.format(c.getTime()));Date timeOut = c.getTime();String token = Jwts.builder().setClaims(o).setExpiration(timeOut).signWith(SignatureAlgorithm.ES256, privateKey).compact();return token;}@Overridepublic String getData(String token) {PublicKey publicKey = getPublicKey();if (publicKey != null) {try {final Claims claims = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token).getBody();Map<String,String> map = (Map<String,String>) claims.get("principal");return map.get( "data" );}catch (Exception e){e.printStackTrace();}}return null;}
}
- Key文件位置
- 测试代码
@Testpublic void createToken (){String token = jwtServiceImpl.createToken( "被封装的数据" );System.out.println("token:"+token);String s = jwtServiceImpl.getData( token );System.out.println(s);}
- 测试结果
随笔记录,方便学习
2020-07-03
这篇关于JWT Token生成与解析 + ECDSA加密技术的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!