私钥和公钥的使用
- 1、私钥
- 1.1、生成密钥证书
- 2、公钥
- 2.1、导出公钥
- 3、测试
- 3.1、使用私钥生成JWT令牌
- 3.2、使用公钥校验JWT令牌
在Spring Security中常用私钥/公钥对来进行安全认证。认证服务使用私钥文件来产生一个JWT令牌,资源服务会保留一份与私钥文件对应的公钥文件,当前端携带JWT令牌来访问资源服务的资源时,资源服务不用再请求认证服务来进行认证,资源服务自己使用公钥文件进行认证,这样既缓解了认证服务的压力,也节省了响应的时间。下面简单介绍一些公钥和私钥的使用。
1、私钥
因为JWT令牌的生成是采用非对称加密算法的,因此可以在认证服务中保留一份私钥文件,这个私钥用来生成JWT。
1.1、生成密钥证书
java提供了一个Keytool工具,这个工具用来提供证书的管理,那么使用Keytool来生成一个密钥文件。如下:
桌面创建一个新的文件夹JWT,空的。进入这个空文件,在当前目录下打开cmd窗口,运行如下命令:
keytool -genkeypair -alias yczkey -keyalg RSA -keypass yanchengzhi -keystore ycz.keystore -storepass ycz123456
参数说明如下:
- -alias:密钥的别名。
- -keyalg:使用hash算法。
- -keypass:密钥的访问密码。
- -keystore:密钥库文件名,ycz.keystore保存了生成的证书。
- -storepass:密钥库的访问密码,注意区分密钥库的访问密码和密钥的访问密码。
按照提示完成输入,这样的结果就是成功了。再看JWT目录:
已经生成了一个私钥文件了,查看内容:
普通文本工具是看不了的。可使用如下命令查看证书信息:
keytool -list -keystore ycz.keystore
证书内容的话还是看不了的,需要专业的工具。
2、公钥
公钥是从私钥中提取出来的,当时生成的时候是生成了公钥/私钥对。公钥文件可以放在资源服务,让资源服务自己来校验JWT令牌的合法性。
2.1、导出公钥
需要借助加解密工具包,这里就用openssl了,它是一个很好的加解密工具包,这个需要先下载,安装完成后的目录如下:
无论下载的是exe文件安装,还是解压zip文件直接使用,一定要确保最后环境变量配置成功了。
要不然openssl的命令是用不了的。检查是否配置成功:
安装配置成功了。
然后可以使用openssl来解密私钥文件了。进入到私钥所在目录,在当前目录下打开cmd窗口,运行以下命令:
keytool -list -rfc --keystore ycz.keystore | openssl x509 -inform pem -pubkey
圈出来的就是公钥的内容,完整复制出来:
贴到文本工具,然后将换行符去掉,整理成一行内容:
一定不要自己加什么东西或者删掉什么内容,要不然最后公钥和私钥配对不上。然后保存为txt文件就行了:
3、测试
下面在程序中测试JWT令牌的生成以及公钥和私钥的配对。
3.1、使用私钥生成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令牌生成成功了。
3.2、使用公钥校验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令牌成功,否则的话内容获取不出来,也间接说明公钥和私钥是匹配上的。