因为JWT令牌的生成是采用非对称加密算法的,因此可以在认证服务中保留一份私钥文件,这个私钥用来生成JWT。
java提供了一个Keytool工具,这个工具用来提供证书的管理,那么使用Keytool来生成一个密钥文件。如下:
桌面创建一个新的文件夹JWT,空的。进入这个空文件,在当前目录下打开cmd窗口,运行如下命令:
keytool -genkeypair -alias yczkey -keyalg RSA -keypass yanchengzhi -keystore ycz.keystore -storepass ycz123456
参数说明如下:
按照提示完成输入,这样的结果就是成功了。再看JWT目录:
已经生成了一个私钥文件了,查看内容:
普通文本工具是看不了的。可使用如下命令查看证书信息:
keytool -list -keystore ycz.keystore
公钥是从私钥中提取出来的,当时生成的时候是生成了公钥/私钥对。公钥文件可以放在资源服务,让资源服务自己来校验JWT令牌的合法性。
需要借助加解密工具包,这里就用openssl了,它是一个很好的加解密工具包,这个需要先下载,安装完成后的目录如下:
无论下载的是exe文件安装,还是解压zip文件直接使用,一定要确保最后环境变量配置成功了。
要不然openssl的命令是用不了的。检查是否配置成功:
安装配置成功了。
然后可以使用openssl来解密私钥文件了。进入到私钥所在目录,在当前目录下打开cmd窗口,运行以下命令:
keytool -list -rfc --keystore ycz.keystore | openssl x509 -inform pem -pubkey
圈出来的就是公钥的内容,完整复制出来:
贴到文本工具,然后将换行符去掉,整理成一行内容:
一定不要自己加什么东西或者删掉什么内容,要不然最后公钥和私钥配对不上。然后保存为txt文件就行了:
下面在程序中测试JWT令牌的生成以及公钥和私钥的配对。
一定要在导入了spring security依赖和oauth依赖的工程中进行测试。
@SpringBootTest
@RunWith(SpringRunner.class)
public class TestMatch {
//测试使用私钥文件生成JWT令牌
@Test
public void testgenerateJwt() {
//证书文件名称
String keystore = "ycz.keystore";
//密钥库密码
String key_store_pass = "ycz123456";
//密钥库文件的位置
ClassPathResource resource = new ClassPathResource(keystore);
//密钥库别名
String alias = "yczkey";
//密钥访问密码
String key_pass = "yanchengzhi";
//创建密钥工厂
KeyStoreKeyFactory keyFactory = new KeyStoreKeyFactory(
resource, key_store_pass.toCharArray());
//获取密钥对(私钥和公钥)
KeyPair keyPair = keyFactory.getKeyPair(alias, key_pass.toCharArray());
//从密钥对中获取私钥
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
//构建JWT令牌的内容
Map<String,Object> body = new HashMap<>();
body.put("name","yanchengzhi");
body.put("address","湖北");
body.put("age",25);
body.put("state","single");
//map转成JSON串
String bodyString = JSON.toJSONString(body);
//使用私钥生成JWT令牌
Jwt jwt = JwtHelper.encode(bodyString, new RsaSigner(privateKey));
//获取JWT令牌
String encode = jwt.getEncoded();
System.out.println(encode);
}
}
执行这个方法,控制台:
JWT令牌生成成功了。
先将公钥文件放进来:
我这里将公钥和私钥文件放在同一个工程下了,为了测试简单点吧,实际上用的时候私钥文件是存放在认证服务中的,公钥文件放在接入了SpringSecurity的资源服务中。
直接在TestMatch类中添加以下内容:
// 测试使用公钥校验JWT令牌
@Test
public void testMatchJwt() {
//jwt令牌,上面生成的直接复制过来
String jwtString = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZGRyZXNzIjoi5rmW5YyXIiwibmFtZSI6InlhbmNoZW5nemhpIiwic3RhdGUiOiJzaW5nbGUiLCJhZ2UiOjI1fQ.lr9qMMrs0YRN-T2TqBsAX3qoIxD6bHqRks6zk1LWwWORMlLQJb4t6RYXJK8fkKOimUPhFzzI828qc4UBsPrJetkT5NWtUFZjhFu-fhpqHgUqi1t_Q_BvJc1nHU5wbdupYxhCu8c8jJ89BB1xkrvaW4y5Queqe2vz2XbDdSDMKHqMKEjOCLCL-1xB8ixCpGRlwRkid5aXhuZu4tK9LTE7pVvX-dKnoElzqBadhD00W1utnietYt0k8Hz-bTDbnWaTjg2ln8-XGu3a2MGnqyPsL70PQmE62etaUj8Ax8yS1nr7AGlLUSShNkjasEDKEgispv8dnIcIMUiEzcDx3toyuw";
//公钥文件名称
String publicKeyName = "publickey.txt";
//获取公钥资源
ClassPathResource resource = new ClassPathResource(publicKeyName);
try {
//获取资源文件
File file = resource.getFile();
//字符输入流
Reader reader = new FileReader(file);
char[] chs = new char[(int) file.length()];
//读取
int len = reader.read(chs);
//获取公钥内容
String public_key = new String(chs,0,len);
//校验JWT
Jwt jwt = JwtHelper.decodeAndVerify(jwtString, new RsaVerifier(public_key));
//获取jwt令牌的内容
String claims = jwt.getClaims();
System.out.println(claims);
//关闭流
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
执行这个方法,控制台:
内容获取出来了,说明公钥校验JWT令牌成功,否则的话内容获取不出来,也间接说明公钥和私钥是匹配上的。