权限认证(六):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令牌
# 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令牌
# 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令牌:使用私钥进行加密,使用公钥进行解密
# 本机安装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
- 配置非对称加密
# 将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令牌
# 进入网站http://slproweb.com/products/Win32OpenSSL.html下载openssl
- 生成公钥
# 下载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);
- 测试