JSON Web Token令牌(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑和自成一体的方式,用于在各方之间作为JSON对象安全地传输信息。这些信息可以被验证和信任,因为它是数字签名的。JWT可以使用密钥(使用HMAC算法)或使用RSA或ECDSA进行公钥/私钥对进行签名。
实际上,我们之前都是携带Token向资源服务器发起请求后,资源服务器由于不知道我们Token的用户信息,所以需要向验证服务器询问此Token的认证信息,这样才能得到Token代表的用户信息,但是各位是否考虑过,如果每次用户请求都去查询用户信息,那么在大量请求下,验证服务器的压力可能会非常的大。而使用JWT之后,Token中会直接保存用户信息,这样资源服务器就不再需要询问验证服务器,自行就可以完成解析,我们的目标是不联系验证服务器就能直接完成验证。
JWT令牌的格式如下:
一个JWT令牌由3部分组成:标头(Header)、有效载荷(Payload)和签名(Signature)。在传输的时候,会将JWT的3部分分别进行Base64编码后用.
进行连接形成最终需要传输的字符串。
这里还是补充一下一些概念,因为很多东西都是我们之前没有接触过的:
=
用来凑够字节数),任何的符号都可以转换成这个字符集中的字符,这个转换过程就叫做Base64编码,编码之后会生成只包含上述64个字符的字符串。相反,如果需要原本的内容,我们也可以进行Base64解码,回到原有的样子。public void test(){ String str = "你们可能不知道只用20万赢到578万是什么概念"; //Base64不只是可以对字符串进行编码,任何byte[]数据都可以,编码结果可以是byte[],也可以是字符串 String encodeStr = Base64.getEncoder().encodeToString(str.getBytes()); System.out.println("Base64编码后的字符串:"+encodeStr); System.out.println("解码后的字符串:"+new String(Base64.getDecoder().decode(encodeStr))); }
注意Base64不是加密算法,只是一种信息的编码方式而已。
这里我们就可以利用jwt,将我们的Token采用新的方式进行存储:
这里我们使用最简单的一种方式,对称密钥,我们需要对验证服务器进行一些修改:
- @Bean
- public JwtAccessTokenConverter tokenConverter(){ //Token转换器,将其转换为JWT
- JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
- converter.setSigningKey("lbwnb"); //这个是对称密钥,一会资源服务器那边也要指定为这个
- return converter;
- }
-
- @Bean
- public TokenStore tokenStore(JwtAccessTokenConverter converter){ //Token存储方式现在改为JWT存储
- return new JwtTokenStore(converter); //传入刚刚定义好的转换器
- }
- @Resource
- TokenStore store;
-
- @Resource
- JwtAccessTokenConverter converter;
-
- private AuthorizationServerTokenServices serverTokenServices(){ //这里对AuthorizationServerTokenServices进行一下配置
- DefaultTokenServices services = new DefaultTokenServices();
- services.setSupportRefreshToken(true); //允许Token刷新
- services.setTokenStore(store); //添加刚刚的TokenStore
- services.setTokenEnhancer(converter); //添加Token增强,其实就是JwtAccessTokenConverter,增强是添加一些自定义的数据到JWT中
- return services;
- }
-
- @Override
- public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
- endpoints
- .tokenServices(serverTokenServices()) //设定为刚刚配置好的AuthorizationServerTokenServices
- .userDetailsService(service)
- .authenticationManager(manager);
- }
然后我们就可以重启验证服务器了:
可以看到成功获取了AccessToken,但是这里的格式跟我们之前的格式就大不相同了,因为现在它是JWT令牌,我们可以对其进行一下Base64解码:
可以看到所有的验证信息包含在内,现在我们对资源服务器进行配置:
- security:
- oauth2:
- resource:
- jwt:
- key-value: lbwnb #注意这里要跟验证服务器的密钥一致,这样算出来的签名才会一致
然后启动资源服务器,请求一下接口试试看:
请求成功,得到数据:
注意如果Token有误,那么会得到: