添加依赖

<dependencies>
<!-- jwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency> <dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.51</version>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency> <dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies> <dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<!--注意这里要加上这些,不然证书无法加载-->
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>**/*.jks</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<includes>
<include>**/*.jks</include>
</includes>
</resource>
</resources> </build>

普通方式创建jwt令牌

package com.example.demo;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm; import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.Date; /**
* @author liuyalong
*/
public class JwtTest { public static void main(String[] args) {
final String keyStr = "4379";
Key key = new SecretKeySpec(keyStr.getBytes(), SignatureAlgorithm.HS512.getJcaName()); // expire_time为token有效时长, 单位毫秒
final long expire_time =10000;
Date expiresDate = new Date(System.currentTimeMillis() + expire_time); //生成jwt令牌
JwtBuilder jwtBuilder = Jwts.builder()
//设置jwt编码
.setId("66")
//设置jwt主题
.setSubject("我是主题")
//设置jwt签发日期
.setIssuedAt(new Date())
.claim("a", "admin")
.claim("b", "aaaa")
.claim("c", "yalong")
//设置jwt的过期时间,好像必须在claim后面
.setExpiration(expiresDate)
//注意,这里的密码应该使用Key类型,不应使用String类型
//如果使用String类型,比如4379123加密,那么解密使用4379也可以解开,
// 因为这个String类型是base64EncodedSecretKey
.signWith(SignatureAlgorithm.HS256, key); //生成jwt
String jwtToken = jwtBuilder.compact();
System.out.println(jwtToken); //解析jwt,得到其内部的数据
Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(jwtToken).getBody();
System.out.println(claims.get("exp"));
System.out.println(claims);
}
}

使用keytool生成证书

keytool -genkeypair -alias test -keyalg RSA -keypass yalong -keystore "D://yalong.jks" -storepass yalong -validity 3650 -dname "CN=localhost,OU=localhost,O=localhost,L=SH,ST=SH,C=CN" -storetype pkcs12

注意:这里有个大坑,keypass 必须和storepass一样,不然私钥解不开,或许是keytool的原因造成的

  • alias:密钥的别名
  • keyalg:使用的hash算法
  • keypass:密钥的访问密码
  • keystore:密钥库文件名,yalong.jks保存了生成的证书
  • storepass:密钥库的访问密码
  • validity 3650 : 有效期10年
  • dname :证书的相关信息,
    • CN:名字与形式
    • OU:组织单位名称
    • O:组织机构名称
    • L:城市信息
    • ST:省份信息
    • C:国家信息

查看密钥库

keytool -list -keystore "D://yalong.jks" -storepass liuyalong

导出公钥证书文件.cer

keytool -export -alias test -keystore "D://yalong.jks" -file "D://publicKey.cer" -storepass yalong

使用密钥对生成JWT并加密解密

使用私钥生成JWT令牌,使用公钥解密,公钥可以公开,私钥留在授权服务里,公钥可以导出,私钥不可以导出

package com.example.demo;

import java.io.FileInputStream;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.interfaces.RSAPrivateKey;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.fastjson.JSON;
import org.apache.commons.codec.binary.Base64;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.RsaSigner;
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
import org.springframework.security.rsa.crypto.KeyStoreKeyFactory; /**
* @author liuyalong
*/
public class GetRsaKey { public static void main(String[] args) throws Exception {
//证书库文件路径
// 这里使用ClassPathResource路径,所以不带D:/
String storePath = "yalong.jks"; //这个路径用来获取私钥
String storePath1 = "D:/yalong.jks"; //公钥证书文件路径
//从keystore 导出公钥证书文件.cer,命令如下
//keytool -export -alias test -keystore "D://yalong.keystore" -file "D://publicKey.cer"
String cerPath = "D:/publicKey.cer"; //证书别名
String alias = "test";
//证书库密码
String storePw = "yalong";
//证书密码
String keyPw = "yalong";
String publicKey = getPublicKey(cerPath);
String privateKey = getPrivateKey(storePath1, alias, storePw, keyPw); System.out.println("从证书获取的公钥为:" + publicKey);
System.out.println("从证书获取的私钥为:" + privateKey); Map<String, String> map = new HashMap<>();
map.put("company", "honbow");
map.put("address", "shenzhen");
String jwt = createJwt(storePath, alias, storePw, keyPw, map);
System.out.println("生成JWT为:" + jwt); String s = parseJwt(jwt, publicKey);
System.out.println("校验后:" + s);
} /**
* 从公钥证书中获取公钥
*
* @param cerPath 公钥证书的路径
*/
private static String getPublicKey(String cerPath) throws Exception {
CertificateFactory certificatefactory = CertificateFactory.getInstance("X.509");
FileInputStream fis = new FileInputStream(cerPath);
// X509Certificate cert = (X509Certificate) certificatefactory.generateCertificate(fis);
Certificate cert = certificatefactory.generateCertificate(fis);
PublicKey pk = cert.getPublicKey();
String pkString = new Base64().encodeToString(pk.getEncoded());
//这里需要拼接开头和结尾,不然无法解析出来结果,可能有其他验证方法
return "-----BEGIN PUBLIC KEY-----" + pkString + "-----END PUBLIC KEY-----";
} private static String getPublicKey(String cerPath, String instanceType) throws Exception {
CertificateFactory certificatefactory = CertificateFactory.getInstance(instanceType);
FileInputStream fis = new FileInputStream(cerPath);
Certificate cert = certificatefactory.generateCertificate(fis);
PublicKey pk = cert.getPublicKey();
return new Base64().encodeToString(pk.getEncoded());
} /**
* @param storePath 证书库的路径
* @param alias 证书别名,创建时指定的
* @param storePw 访问证书库的密码
* @param keyPw 访问证书的密码
* @param JwtMap 需要设置进Jwt的内容
* @return jwt 字符串
*/
private static String createJwt(String storePath,
String alias,
String storePw,
String keyPw,
Map<String, String> JwtMap) { ClassPathResource classPathResource = new ClassPathResource(storePath); KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(classPathResource, keyPw.toCharArray()); KeyPair keyPair = keyStoreKeyFactory.getKeyPair(alias, storePw.toCharArray()); //将当前的私钥转换为rsa私钥
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
Jwt jwt = JwtHelper.encode(JSON.toJSONString(JwtMap), new RsaSigner(rsaPrivateKey));
return jwt.getEncoded();
} /**
* 生成私钥
*
* @param storePath 证书库的路径
* @param alias 证书别名,创建时指定的
* @param storePw 访问证书库的密码
* @param keyPw 访问证书的密码
*/
private static String getPrivateKey(String storePath, String alias, String storePw, String keyPw) throws Exception {
FileInputStream is = new FileInputStream(storePath);
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(is, storePw.toCharArray());
is.close();
PrivateKey key = (PrivateKey) ks.getKey(alias, keyPw.toCharArray());
return new Base64().encodeToString(key.getEncoded());
} private static String getPrivateKey(String storePath, String alias, String storePw, String keyPw, String storeType) throws Exception {
FileInputStream is = new FileInputStream(storePath);
KeyStore ks = KeyStore.getInstance(storeType);
ks.load(is, storePw.toCharArray());
is.close();
PrivateKey key = (PrivateKey) ks.getKey(alias, keyPw.toCharArray());
return new Base64().encodeToString(key.getEncoded());
} /**
* @param jwt jwt字符串
* @param publicKey 公钥
* @return 解密后的字符串token
*/
private static String parseJwt(String jwt, String publicKey) { Jwt token = JwtHelper.decodeAndVerify(jwt, new RsaVerifier(publicKey)); return token.getClaims();
}
}

RSA的公钥和私钥到底哪个才是用来加密和哪个用来解密?

  • 既然是加密,那肯定是不希望别人知道我的消息,所以只有我才能解密,所以可得出公钥负责加密,私钥负责解密;同理,既然是签名,那肯定是不希望有人冒充我发消息,只有我才能发布这个签名,所以可得出私钥负责签名,公钥负责验证。

注:

JWT保证的是数据传输过程中的完整性而不是机密性。

由于payload是使用base64url编码的,所以相当于明文传输,如果在payload中携带了敏感信息(如存放密钥对的文件路径),单独对payload部分进行base64url解码,就可以读取到payload中携带的信息。

Jwt令牌创建的更多相关文章

  1. Spring Boot Security OAuth2 实现支持JWT令牌的授权服务器

    概要 之前的两篇文章,讲述了Spring Security 结合 OAuth2 .JWT 的使用,这一节要求对 OAuth2.JWT 有了解,若不清楚,先移步到下面两篇提前了解下. Spring Bo ...

  2. 阶段5 3.微服务项目【学成在线】_day16 Spring Security Oauth2_13-SpringSecurityOauth2研究-JWT研究-生成JWT令牌&验证JWT令牌

    生成jwt需要用私钥来签名.在Auth认证服务下创建测试类 创建密钥工厂,构造函数需要的参数 获取私钥 有了私钥就可以生成JWT令牌 使用jwtHelper是spring security里面的类 e ...

  3. 什么是JWT令牌认证?

    当下,JWT(JSON Web Token)令牌认证已经变得越来越流行.本文主要介绍JWT令牌认证与传统的Session会话认证机制的区别. 为什么需要认证? HTTP是一种无状态协议,那就意味着当前 ...

  4. 畅购商城(八):微服务网关和JWT令牌

    好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/RobodLee/DayDayUP,欢迎Star,更多文章请前往:目录导航 畅购商城(一):环境搭建 畅购商 ...

  5. Spring Security OAuth2.0认证授权三:使用JWT令牌

    Spring Security OAuth2.0系列文章: Spring Security OAuth2.0认证授权一:框架搭建和认证测试 Spring Security OAuth2.0认证授权二: ...

  6. JWT令牌简介及demo

    一.访问令牌的类型 二.JWT令牌 1.什么是JWT令牌 ​ JWT是JSON Web Token的缩写,即JSON Web令牌,是一种自包含令牌. JWT的使用场景: 一种情况是webapi,类似之 ...

  7. spring security oauth2搭建resource-server demo及token改造成JWT令牌

    我们在上文讲了如何在spring security的环境中搭建基于oauth2协议的认证中心demo:https://www.cnblogs.com/process-h/p/15688971.html ...

  8. 微服务架构 | 7.2 构建使用 JWT 令牌存储的 OAuth2 安全认证

    目录 前言 1. JWT 令牌存储基础知识 1.1 JSON Web Token 2. 构建使用 JWT 令牌存储的 OAuth2 服务器 2.1 引入 pom.xml 依赖文件 2.2 创建 JWT ...

  9. 阶段5 3.微服务项目【学成在线】_day18 用户授权_03-方法授权-jwt令牌包含权限

    修改认证服务的UserDetailServiceImpl类,下边的代码中 permissionList列表中存放了用户的权限, 并且将权限标识按照中间使用逗号分隔的语法组成一个字符串,最终提供给Spr ...

随机推荐

  1. Hadoop大数据平台节点的动态增删

    环境:CentOS 7.4 (1708  DVD) 工具:MobaXterm 一. 节点的动态增加 1. 为新增加的节点(主机)配置免密码登录.使用ssh-keygen和ssh-copy-id命令(详 ...

  2. 计算机&编程语言发展史

    计算机&编程语言发展史 编辑于2020-11-18 计算机的基本组成 计算机的发展经历了哪几代? 第一代 电子管计算机 第二代 晶体管计算机 第三代 集成电路计算机 第四代 大规模和超大规模集 ...

  3. 使用Camtasia制作魔性抖肩舞视频

    最近一首风魔各大视频网站的魔性舞蹈又来袭了!这首充满魔性节奏的舞蹈就是抖肩舞了,为了将我热爱的抖肩舞视频分享给大家,我必须使用Camtasia教程录制(Windows系统)软件来制作一个魔性抖肩舞视频 ...

  4. 基于gin的golang web开发:永远不要相信用户的输入

    作为后端开发者我们要记住一句话:"永远不要相信用户的输入",这里所说的用户可能是人,也可能是另一个应用程序."永远不要相信用户的输入"是安全编码的准则,也就是说 ...

  5. python3基础3

    # 匿名函数: bbb = lambda a, b: a + b print(bbb(1,1)) # 函数 def add(a=None, b=None): """ 接收 ...

  6. P3619 魔法

    考虑两个任务 \(1\) 和 \(2\),当前时间为 \(T\),两个任务都要完成. 先完成任务 \(1\) 的条件是 \(T>t_1\) 且 \(T+b_1>t_2\),先完成任务 \( ...

  7. 【AcWing 113】【交互】特殊排序——二分

    (题面来自AcWing) 有N个元素,编号1.2..N,每一对元素之间的大小关系是确定的,关系不具有传递性. 也就是说,元素的大小关系是N个点与N*(N-1)/2条有向边构成的任意有向图. 然而,这是 ...

  8. C语言讲义——头文件

    头文件.h Dev C++可以建C项目,也可以建C++项目,下面分C和C++两种情况讨论. c.h C语言中,头文件往往不是必须的,只是描述性的文件. 因此,C项目中可以没有.h文件. cpp.h 下 ...

  9. 通过Consul Raft库打造自己的分布式系统

    通用的CP系统有etcd和consul, 通用的对立面就是专用系统. 所以在某些场合是有这种需求的. 然而etcd embed的可用性极差, Windows上面跑会出现各种问题, 而且不能定制协议, ...

  10. transform的2D和3D变换

    transform取值 none:默认值,即是无转换 matrix(,,,,,): 以一个含六值的(a,b,c,d,e,f)变换矩阵的形式指定一个2D变换,相当于直接应用一个[a,b,c,d,e,f] ...