天天看点

权限认证(六):JWT 访问令牌使用对称与非对称加密

  • jwt简介
# 头部:包含令牌的类型(JWT) 与加密的签名算法((如 SHA256 或 ES256) ,Base64编码后加入第一部分
# 有效载荷:通俗一点讲就是token中需要携带的信息都将存于此部分,比如:用户id、权限标识等信息。
注:该部分信息任何人都可以读出来,所以添加的信息需要加密才会保证信息的安全性
# 签名:用于防止 JWT 内容被篡改, 会将头部和有效载荷分别进行 Base64编码,编码后用 . 连接组成新的字符串,然后再使用头部声明的签名算法进行签名。在具有秘钥的情况下,可以验证JWT的准确性,是否被篡改      
  • 在demo06的基础上开发,首先测试通过
# 获取授权码
http://localhost:8090/auth/oauth/authorize?client_id=mengxuegu-pc&response_type=code      
权限认证(六):JWT 访问令牌使用对称与非对称加密
权限认证(六):JWT 访问令牌使用对称与非对称加密
权限认证(六):JWT 访问令牌使用对称与非对称加密
权限认证(六):JWT 访问令牌使用对称与非对称加密
权限认证(六):JWT 访问令牌使用对称与非对称加密
权限认证(六):JWT 访问令牌使用对称与非对称加密
  • ​在认证服务器中使用对称加密jwt令牌​

# server子模块中的TokenConfig中配置如下
    public static final String SIGNING_KEY = "mengxeugu-key";
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        // 对称加密进行签名令牌,资源服务器也要采用此密钥来进行解密,来校验令牌合法性
        converter.setSigningKey(SIGNING_KEY);
        return converter;
    }
    @Bean
    public TokenStore tokenStore() {
        // jdbc管理令牌
        //return new JdbcTokenStore(dataSource());
        // Jwt管理令牌
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

# server子模块中的AuthorizationServerConfig中配置如下
@Autowired // jwt转换器
    private JwtAccessTokenConverter jwtAccessTokenConverter;
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        // 令牌的管理方式
        //endpoints.tokenStore(tokenStore);
        endpoints.tokenStore(tokenStore).accessTokenConverter(jwtAccessTokenConverter);
    }      
  • 启动认证服务器和资源服务器测试
  • 使用密码模式获取一个token
  • 权限认证(六):JWT 访问令牌使用对称与非对称加密
  • 检查该令牌
  • 权限认证(六):JWT 访问令牌使用对称与非对称加密
  • ​资源服务器对称解密jwt令牌​

# resource子模块中配置TokenConfig
@Configuration
public class TokenConfig {
    public static final String SIGNING_KEY = "mengxeugu-key";
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        // 对称加密进行签名令牌,资源服务器也要采用此密钥来进行解密,来校验令牌合法性
        converter.setSigningKey(SIGNING_KEY);
        // 非对称加密,资源服务器使用公钥解密 public.txt
//        ClassPathResource resource = new ClassPathResource("public.txt");
//        String publicKey = null;
//        try {
//            publicKey = IOUtils.toString(resource.getInputStream(), "UTF-8");
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        converter.setVerifierKey(publicKey);
        return converter;
    }
    @Bean
    public TokenStore tokenStore() {
        // Jwt管理令牌
        return new JwtTokenStore(jwtAccessTokenConverter());
    }
}

# ResourceServerConfig中配置如下
# 删除如下
public ResourceServerTokenServices tokenService(){
//        // 远程认证服务器进行校验 token 是否有效
//        RemoteTokenServices service = new RemoteTokenServices();
//        // 请求认证服务器校验的地址,默认情况 这个地址在认证服务器它是拒绝访问,要设置为认证通过可访问
//        service.setCheckTokenEndpointUrl("http://localhost:8090/auth/oauth/check_token");
//        service.setClientId("mengxuegu-pc");
//        service.setClientSecret("mengxuegu-secret");
//        return service;
//    }

.tokenServices(tokenService())

# 添加如下
@Autowired
private TokenStore tokenStore;

.tokenStore(tokenStore)      
  • 测试
  • 权限认证(六):JWT 访问令牌使用对称与非对称加密
    权限认证(六):JWT 访问令牌使用对称与非对称加密
  • ​认证服务器非对称加密jwt令牌:使用私钥进行加密,使用公钥进行解密​

# 本机安装jdk后,生成密钥
# 打开cmd,生成密钥时显示'keytool' 不是内部或外部命令,也不是可运行的程序,需进入C:\Program Files\Java\jdk-11.0.13\bin目录进行操作
# 报错:keytool 错误: java.io.FileNotFoundException: oauth2.jks (拒绝访问。),解决方案是以管理员身份进入jdk目录进行操作
# 以管理员的身份进入C:\Program Files\Java\jdk-11.0.13\bin目录,执行如下命令
keytool -genkeypair -alias oauth2 -keyalg RSA -keypass oauth2 -keystore oauth2.jks
-storepass oauth2

# 口令:oauth2
# 姓氏:meng
# 组织:mxg
# 城市:bj
# 国家:cn
# 是否确认:y

# 在执行命令的路径下生成oauth2.jks      
权限认证(六):JWT 访问令牌使用对称与非对称加密
  • 配置非对称加密
# 将oauth2.jks剪切到认证服务器子模块的resource目录下

# TokenConfig中配置如下
KeyStoreKeyFactory factory = new KeyStoreKeyFactory(
                new ClassPathResource("oauth2.jks"), "oauth2".toCharArray());
        converter.setKeyPair(factory.getKeyPair("oauth2"));

# 删除如下
converter.setSigningKey(SIGNING_KEY);      
  • 拓展
keytool 
-genkeypair -alias oauth2 # 设置别名oauth2
-keyalg RSA -keypass oauth2 # 设置keypass为oauth2
-keystore oauth2.jks # 设置生成的文件名oauth2.jks
-storepass oauth2

KeyStoreKeyFactory factory = new KeyStoreKeyFactory(
                new ClassPathResource("oauth2.jks"),  # 加载oauth2.jks文件
                "oauth2".toCharArray()); # 使用之前设置的keypass
        converter.setKeyPair(factory.getKeyPair("oauth2")); # 使用之前设置的别名      
  • 测试:启动认证服务器和资源服务器
  • 权限认证(六):JWT 访问令牌使用对称与非对称加密
  • ​资源服务器非对称解密jwt令牌​

# 进入网站http://slproweb.com/products/Win32OpenSSL.html下载openssl      
权限认证(六):JWT 访问令牌使用对称与非对称加密
  • 生成公钥
# 下载openssl后双击直接安装
# 配置环境变量:Path = C:\Program Files\OpenSSL-Win64\bin
# 将之前生成oauth2.jks发到c盘根目录下,以管理员的身份进入C:\Program Files\Java\jdk-11.0.13\bin目录执行如下命令生成公钥
C:\Program Files\Java\jdk-11.0.13\bin>keytool -list -rfc --keystore C:\oauth2.jks | openssl x509 -inform pem -pubkey
输入密钥库口令:  oauth2
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArws0jvq7ciIW1ea7IZwm
kk4CxWKTk0R9hwZO1hEQA5+9hDs+mBBfYpw6kYETLtgGtDm8ayLnbMoq6sTkOELN
1nYj1fIqffQCKKzBiiTMa9VDndLnATHIZpCOHnzqOPZBFg5TrQV0xMyWU9FT8qRB
GsntUdeI21tk/cN6rmVnDEGkFJmpT7JO+MlDMN6wAeANUUk+gZql/ZX8Hzn+xZrv
qYZ3HLCKFpRFbp/+b39d7VS8CwjP5Q1GtJKrVMAJ/Vm6GaQKtvsGDjkGj1E+lfDV
szbnK/p6R7B9ynXUvEDXkEjAnzTjJLL05MJdYbS3Osd7cSAcHB8pzHXD5WbpYWeJ
JQIDAQAB
-----END PUBLIC KEY-----
-----BEGIN CERTIFICATE-----
MIIDQzCCAiugAwIBAgIEK51NDzANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJj
bjELMAkGA1UECBMCd3oxCzAJBgNVBAcTAmJqMQwwCgYDVQQKEwNteGcxDDAKBgNV
BAsTA214ZzENMAsGA1UEAxMEbWVuZzAeFw0yMjA0MDQwMjE0MDJaFw0yMjA3MDMw
MjE0MDJaMFIxCzAJBgNVBAYTAmNuMQswCQYDVQQIEwJ3ejELMAkGA1UEBxMCYmox
DDAKBgNVBAoTA214ZzEMMAoGA1UECxMDbXhnMQ0wCwYDVQQDEwRtZW5nMIIBIjAN
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArws0jvq7ciIW1ea7IZwmkk4CxWKT
k0R9hwZO1hEQA5+9hDs+mBBfYpw6kYETLtgGtDm8ayLnbMoq6sTkOELN1nYj1fIq
ffQCKKzBiiTMa9VDndLnATHIZpCOHnzqOPZBFg5TrQV0xMyWU9FT8qRBGsntUdeI
21tk/cN6rmVnDEGkFJmpT7JO+MlDMN6wAeANUUk+gZql/ZX8Hzn+xZrvqYZ3HLCK
FpRFbp/+b39d7VS8CwjP5Q1GtJKrVMAJ/Vm6GaQKtvsGDjkGj1E+lfDVszbnK/p6
R7B9ynXUvEDXkEjAnzTjJLL05MJdYbS3Osd7cSAcHB8pzHXD5WbpYWeJJQIDAQAB
oyEwHzAdBgNVHQ4EFgQUA7Y9cGQZshEWO/WaGLtdxRkP1wcwDQYJKoZIhvcNAQEL
BQADggEBAD7ZCX02zuHcjaaod0UH2cKc7z2eCZl35IshGbEpJQ1TiQ4Rl9I4mDh+
kQjLEeMbAD9LM2N/0kpSfBPvc0b2qFuU8hLqmfDWC2TAF1st9EGx+i+b1m9sXaDl
2QgSvyt5KE81NxlnS5PpLDuFl2Bv/8RD4KSmdzM2zF+EFuYr1ZxNEoi5JIKxFcjF
JRYQSzLLL9sCLO5B+YXuobY7UW42oi0guWvVFuzkSrsEZb3gyZjbkWOXFXUPZCIK
H83FJWe0JytXziUhwdrwIDaTo4Q4mSJfYTRyKDKnwrGq0aWN3OTOzWtQpNu/9HLk
Wv5Gx47xMdHHHwffUliFSB24HvqVuG8=
-----END CERTIFICATE-----      
  • 在资源服务器的resource目录下新建public.txt
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArws0jvq7ciIW1ea7IZwm
kk4CxWKTk0R9hwZO1hEQA5+9hDs+mBBfYpw6kYETLtgGtDm8ayLnbMoq6sTkOELN
1nYj1fIqffQCKKzBiiTMa9VDndLnATHIZpCOHnzqOPZBFg5TrQV0xMyWU9FT8qRB
GsntUdeI21tk/cN6rmVnDEGkFJmpT7JO+MlDMN6wAeANUUk+gZql/ZX8Hzn+xZrv
qYZ3HLCKFpRFbp/+b39d7VS8CwjP5Q1GtJKrVMAJ/Vm6GaQKtvsGDjkGj1E+lfDV
szbnK/p6R7B9ynXUvEDXkEjAnzTjJLL05MJdYbS3Osd7cSAcHB8pzHXD5WbpYWeJ
JQIDAQAB
-----END PUBLIC KEY-----      
  • 配置如下
# resource子模块TokenConfig配置如下
# 删除如下:
converter.setSigningKey(SIGNING_KEY);
# 添加如下:
ClassPathResource resource = new ClassPathResource("public.txt");
String publicKey = null;
try {
    publicKey = IOUtils.toString(resource.getInputStream(), "UTF-8");
} catch (IOException e) {
    e.printStackTrace();
}
converter.setVerifierKey(publicKey);      
  • 测试
  • 权限认证(六):JWT 访问令牌使用对称与非对称加密