私钥和公钥的使用

  • 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来生成一个密钥文件。如下:

spring vaullt spring vaullt 秘钥管理_Test


桌面创建一个新的文件夹JWT,空的。进入这个空文件,在当前目录下打开cmd窗口,运行如下命令:

keytool -genkeypair -alias yczkey -keyalg RSA -keypass yanchengzhi -keystore ycz.keystore -storepass ycz123456

参数说明如下:

  • -alias:密钥的别名。
  • -keyalg:使用hash算法。
  • -keypass:密钥的访问密码。
  • -keystore:密钥库文件名,ycz.keystore保存了生成的证书。
  • -storepass:密钥库的访问密码,注意区分密钥库的访问密码和密钥的访问密码。

按照提示完成输入,这样的结果就是成功了。再看JWT目录:

spring vaullt spring vaullt 秘钥管理_Test_02


已经生成了一个私钥文件了,查看内容:

spring vaullt spring vaullt 秘钥管理_Test_03


普通文本工具是看不了的。可使用如下命令查看证书信息:

keytool -list -keystore ycz.keystore

spring vaullt spring vaullt 秘钥管理_JSON_04


证书内容的话还是看不了的,需要专业的工具。

2、公钥

公钥是从私钥中提取出来的,当时生成的时候是生成了公钥/私钥对。公钥文件可以放在资源服务,让资源服务自己来校验JWT令牌的合法性。

2.1、导出公钥

需要借助加解密工具包,这里就用openssl了,它是一个很好的加解密工具包,这个需要先下载,安装完成后的目录如下:

spring vaullt spring vaullt 秘钥管理_JSON_05


无论下载的是exe文件安装,还是解压zip文件直接使用,一定要确保最后环境变量配置成功了。

spring vaullt spring vaullt 秘钥管理_文件名_06


spring vaullt spring vaullt 秘钥管理_JSON_07


要不然openssl的命令是用不了的。检查是否配置成功:

spring vaullt spring vaullt 秘钥管理_JSON_08


安装配置成功了。

然后可以使用openssl来解密私钥文件了。进入到私钥所在目录,在当前目录下打开cmd窗口,运行以下命令:

keytool -list -rfc --keystore ycz.keystore | openssl x509 -inform pem -pubkey


圈出来的就是公钥的内容,完整复制出来:

spring vaullt spring vaullt 秘钥管理_文件名_09


贴到文本工具,然后将换行符去掉,整理成一行内容:

spring vaullt spring vaullt 秘钥管理_文件名_10


spring vaullt spring vaullt 秘钥管理_spring vaullt_11


spring vaullt spring vaullt 秘钥管理_文件名_12


一定不要自己加什么东西或者删掉什么内容,要不然最后公钥和私钥配对不上。然后保存为txt文件就行了:

spring vaullt spring vaullt 秘钥管理_JSON_13

3、测试

下面在程序中测试JWT令牌的生成以及公钥和私钥的配对。

3.1、使用私钥生成JWT令牌

一定要在导入了spring security依赖和oauth依赖的工程中进行测试。

先将私钥文件放进来:

spring vaullt spring vaullt 秘钥管理_JSON_14


直接在测试类中写:

@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);
    }

}

执行这个方法,控制台:

spring vaullt spring vaullt 秘钥管理_JSON_15


JWT令牌生成成功了。

3.2、使用公钥校验JWT令牌

先将公钥文件放进来:

spring vaullt spring vaullt 秘钥管理_JSON_16


我这里将公钥和私钥文件放在同一个工程下了,为了测试简单点吧,实际上用的时候私钥文件是存放在认证服务中的,公钥文件放在接入了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();
        }
    }

执行这个方法,控制台:

spring vaullt spring vaullt 秘钥管理_文件名_17


内容获取出来了,说明公钥校验JWT令牌成功,否则的话内容获取不出来,也间接说明公钥和私钥是匹配上的。