SpringSecurityOAuth使用JWT Token

⒈JWT?

  JWT(Json Web Token),是Json的一个开放的Token标准。

    1,自包含,SpringSecurityOAuth的默认Token是UUID的一个随机的无意义的字符串,并不包含任何信息,信息是被单独存放的,我们还需要通过这个令牌从单独存放信息的存储那里获取信息,所以说SpringSecurityOAuth的默认Token比较依赖于存储,一旦存储信息的存储那里出现了故障,那么这个令牌就毫无用处了。而JWT Token中是包含有意义的信息的,当我们的系统拿到这个令牌以后,我们可以直接解析这个令牌来获取有用的信息。

    2,密签,我们可以对发出去的令牌进行签名(指令牌被人篡改我们可以获知)

    3,可扩展,Token中的信息我们可以根据业务需求进行扩展。

⒉如何在SpringSecurityOAuth中使用JWT Token替换掉默认的UUID Token

  1.

 1         <dependency>
 2             <groupId>org.springframework.boot</groupId>
 3             <artifactId>spring-boot-starter-security</artifactId>
 4         </dependency>
 5         <dependency>
 6             <groupId>org.springframework.boot</groupId>
 7             <artifactId>spring-boot-starter-data-redis</artifactId>
 8         </dependency>
 9         <dependency>
10             <groupId>org.springframework.boot</groupId>
11             <artifactId>spring-boot-starter-web</artifactId>
12         </dependency>
13         <dependency>
14             <groupId>org.springframework.security.oauth</groupId>
15             <artifactId>spring-security-oauth2</artifactId>
16             <version>2.3.5.RELEASE</version>
17         </dependency>
18         <dependency>
19             <groupId>commons-collections</groupId>
20             <artifactId>commons-collections</artifactId>
21             <version>3.2.2</version>
22         </dependency>
23         <dependency>
24             <groupId>org.springframework.boot</groupId>
25             <artifactId>spring-boot-starter-test</artifactId>
26             <scope>test</scope>
27         </dependency>
28         <dependency>
29             <groupId>org.springframework.security</groupId>
30             <artifactId>spring-security-test</artifactId>
31             <scope>test</scope>
32         </dependency>

  2.

 1 package cn.coreqi.config;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.context.annotation.Bean;
 5 import org.springframework.context.annotation.Conditional;
 6 import org.springframework.context.annotation.Configuration;
 7 import org.springframework.data.redis.connection.RedisConnectionFactory;
 8 import org.springframework.security.oauth2.provider.token.TokenStore;
 9 import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
10 import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
11 import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
12 
13 @Configuration
14 public class TokenStoreConfig {
15 
16     @Autowired
17     private RedisConnectionFactory redisConnectionFactory;
18 
19     /**
20      * TokenStore 负责令牌的存取
21      * @return
22      */
23 //    @Bean
24 //    public TokenStore redisTokenStore(){
25 //        return new RedisTokenStore(redisConnectionFactory);
26 //    }
27 
28     @Configuration
29     public static class JwtTokenConfig {
30         /**
31          * Token生成中的处理
32          * @return
33          */
34         @Bean
35         public JwtAccessTokenConverter jwtAccessTokenConverter(){
36             JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
37             accessTokenConverter.setSigningKey("fanqi");   //Token签名用的密钥
38             //发出去的令牌需要密钥签名,验令牌的时候也需要令牌来验签,如果他人获知了我们的密钥
39             //就可以用我们的密钥来签发我们的JWT令牌,JWT唯一的安全性就是密钥
40             //别人用我们的密钥来签发我们的JWT令牌就可以随意进入我们的系统
41             return accessTokenConverter;
42         }
43 
44         @Bean
45         public TokenStore jwtTokenStore(){
46             return new JwtTokenStore(jwtAccessTokenConverter());
47         }
48     }
49 }

  3.

 1 package cn.coreqi.config;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.beans.factory.annotation.Qualifier;
 5 import org.springframework.context.annotation.Bean;
 6 import org.springframework.context.annotation.Configuration;
 7 import org.springframework.data.redis.connection.RedisConnectionFactory;
 8 import org.springframework.security.authentication.AuthenticationManager;
 9 import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
10 import org.springframework.security.core.userdetails.UserDetailsService;
11 import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
12 import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
13 import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
14 import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
15 import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
16 import org.springframework.security.oauth2.provider.token.TokenStore;
17 import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
18 import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
19 
20 @Configuration
21 @EnableAuthorizationServer  //开启认证服务器
22 public class CoreqiAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
23 
24     @Autowired
25     //@Qualifier("authenticationManagerBean")
26     private AuthenticationManager authenticationManager;
27 
28     @Autowired
29     private UserDetailsService userDetailsService;
30 
31 
32     @Autowired
33     private TokenStore jwtTokenStore;
34 
35     @Autowired(required = false)
36     private JwtAccessTokenConverter jwtAccessTokenConverter;
37 
38 //    @Autowired
39 //    private AuthenticationConfiguration authenticationConfiguration;
40 
41     /**
42      * 针对端点的配置
43      * @param authorizationServerEndpointsConfigurer
44      * @throws Exception
45      */
46     @Override
47     public void configure(AuthorizationServerEndpointsConfigurer authorizationServerEndpointsConfigurer) throws Exception {
48         //authorizationServerEndpointsConfigurer.authenticationManager(authenticationConfiguration.getAuthenticationManager());
49         authorizationServerEndpointsConfigurer.tokenStore(jwtTokenStore)  //使用JwtToken
50                                             .authenticationManager(authenticationManager)
51                                             .userDetailsService(userDetailsService);
52         if(jwtAccessTokenConverter != null){
53             authorizationServerEndpointsConfigurer.accessTokenConverter(jwtAccessTokenConverter);
54         }
55     }
56 
57     /**
58      * 第三方应用客户端的有关配置
59      * @param clientDetailsServiceConfigurer
60      * @throws Exception
61      */
62     @Override
63     public void configure(ClientDetailsServiceConfigurer clientDetailsServiceConfigurer) throws Exception {
64         clientDetailsServiceConfigurer.inMemory()
65                 .withClient("coreqi")   //client_id
66                 .secret("coreqiSecret") //client_id的密码
67                 .accessTokenValiditySeconds(7200) //令牌的有效时间(单位秒)
68                 .redirectUris("https://www.baidu.com")
69                 .scopes("all","read","write")  //所支持的权限有那些
70                 .authorities("COREQI_READ")
71                 .authorizedGrantTypes("authorization_code","password"); //针对当前client所支持的授权模式
72     }
73 
74     /**
75      * 针对安全性有关的配置
76      * @param security
77      * @throws Exception
78      */
79     @Override
80     public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
81         super.configure(security);
82     }
83 }

⒊如何扩展Jwt Token中的信息

 1 package cn.coreqi.jwt;
 2 
 3 import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
 4 import org.springframework.security.oauth2.common.OAuth2AccessToken;
 5 import org.springframework.security.oauth2.provider.OAuth2Authentication;
 6 import org.springframework.security.oauth2.provider.token.TokenEnhancer;
 7 
 8 import java.util.HashMap;
 9 import java.util.Map;
10 
11 public class CoreqiJwtTokenEnhancer implements TokenEnhancer {
12 
13     @Override
14     public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
15         Map<String,Object> info = new HashMap<>();  //要往accessToken中存放的信息
16         info.put("company","fanqi");
17         ((DefaultOAuth2AccessToken)accessToken).setAdditionalInformation(info); //设置附加信息
18         return accessToken;
19     }
20 }
 1 package cn.coreqi.config;
 2 
 3 import cn.coreqi.jwt.CoreqiJwtTokenEnhancer;
 4 import org.springframework.beans.factory.annotation.Autowired;
 5 import org.springframework.context.annotation.Bean;
 6 import org.springframework.context.annotation.Conditional;
 7 import org.springframework.context.annotation.Configuration;
 8 import org.springframework.data.redis.connection.RedisConnectionFactory;
 9 import org.springframework.security.oauth2.provider.token.TokenEnhancer;
10 import org.springframework.security.oauth2.provider.token.TokenStore;
11 import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
12 import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
13 import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
14 
15 @Configuration
16 public class TokenStoreConfig {
17 
18     @Autowired
19     private RedisConnectionFactory redisConnectionFactory;
20 
21     /**
22      * TokenStore 负责令牌的存取
23      * @return
24      */
25 //    @Bean
26 //    public TokenStore redisTokenStore(){
27 //        return new RedisTokenStore(redisConnectionFactory);
28 //    }
29 
30     @Configuration
31     public static class JwtTokenConfig {
32         /**
33          * Token生成中的处理
34          * @return
35          */
36         @Bean
37         public JwtAccessTokenConverter jwtAccessTokenConverter(){
38             JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
39             accessTokenConverter.setSigningKey("fanqi");   //Token签名用的密钥
40             //发出去的令牌需要密钥签名,验令牌的时候也需要令牌来验签,如果他人获知了我们的密钥
41             //就可以用我们的密钥来签发我们的JWT令牌,JWT唯一的安全性就是密钥
42             //别人用我们的密钥来签发我们的JWT令牌就可以随意进入我们的系统
43             return accessTokenConverter;
44         }
45 
46         @Bean
47         public TokenStore jwtTokenStore(){
48             return new JwtTokenStore(jwtAccessTokenConverter());
49         }
50 
51         @Bean
52         public TokenEnhancer jwtTokenEnhancer(){
53             return new CoreqiJwtTokenEnhancer();
54         }
55     }
56 }
 1 package cn.coreqi.config;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.beans.factory.annotation.Qualifier;
 5 import org.springframework.context.annotation.Bean;
 6 import org.springframework.context.annotation.Configuration;
 7 import org.springframework.data.redis.connection.RedisConnectionFactory;
 8 import org.springframework.security.authentication.AuthenticationManager;
 9 import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
10 import org.springframework.security.core.userdetails.UserDetailsService;
11 import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
12 import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
13 import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
14 import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
15 import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
16 import org.springframework.security.oauth2.provider.token.TokenEnhancer;
17 import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
18 import org.springframework.security.oauth2.provider.token.TokenStore;
19 import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
20 import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
21 
22 import java.util.ArrayList;
23 import java.util.List;
24 
25 @Configuration
26 @EnableAuthorizationServer  //开启认证服务器
27 public class CoreqiAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
28 
29     @Autowired
30     //@Qualifier("authenticationManagerBean")
31     private AuthenticationManager authenticationManager;
32 
33     @Autowired
34     private UserDetailsService userDetailsService;
35 
36 
37     @Autowired
38     private TokenStore jwtTokenStore;
39 
40     @Autowired(required = false)
41     private JwtAccessTokenConverter jwtAccessTokenConverter;
42 
43     @Autowired(required = false)
44     private TokenEnhancer jwtTokenEnhancer;
45 
46 //    @Autowired
47 //    private AuthenticationConfiguration authenticationConfiguration;
48 
49     /**
50      * 针对端点的配置
51      * @param authorizationServerEndpointsConfigurer
52      * @throws Exception
53      */
54     @Override
55     public void configure(AuthorizationServerEndpointsConfigurer authorizationServerEndpointsConfigurer) throws Exception {
56         //authorizationServerEndpointsConfigurer.authenticationManager(authenticationConfiguration.getAuthenticationManager());
57         authorizationServerEndpointsConfigurer.tokenStore(jwtTokenStore)  //使用JwtToken
58                                             .authenticationManager(authenticationManager)
59                                             .userDetailsService(userDetailsService);
60         if(jwtAccessTokenConverter != null && jwtTokenEnhancer != null){
61             TokenEnhancerChain enhancerChain = new TokenEnhancerChain();    //Token增强器
62             List<TokenEnhancer> enhancers = new ArrayList<>();
63             enhancers.add(jwtTokenEnhancer);
64             enhancers.add(jwtAccessTokenConverter);
65             enhancerChain.setTokenEnhancers(enhancers);
66             authorizationServerEndpointsConfigurer.tokenEnhancer(enhancerChain)
67                     .accessTokenConverter(jwtAccessTokenConverter);
68         }
69     }
70 
71     /**
72      * 第三方应用客户端的有关配置
73      * @param clientDetailsServiceConfigurer
74      * @throws Exception
75      */
76     @Override
77     public void configure(ClientDetailsServiceConfigurer clientDetailsServiceConfigurer) throws Exception {
78         clientDetailsServiceConfigurer.inMemory()
79                 .withClient("coreqi")   //client_id
80                 .secret("coreqiSecret") //client_id的密码
81                 .accessTokenValiditySeconds(7200) //令牌的有效时间(单位秒)
82                 .redirectUris("https://www.baidu.com")
83                 .scopes("all","read","write")  //所支持的权限有那些
84                 .authorities("COREQI_READ")
85                 .authorizedGrantTypes("authorization_code","password"); //针对当前client所支持的授权模式
86     }
87 
88     /**
89      * 针对安全性有关的配置
90      * @param security
91      * @throws Exception
92      */
93     @Override
94     public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
95         super.configure(security);
96     }
97 }

⒋控制器如何识别Token中扩展的信息

1 <dependency>
2     <groupId>io.jsonwebtoken</groupId>
3     <artifactId>jjwt</artifactId>
4     <version>0.9.1</version>
5 </dependency>
 1 package cn.coreqi.controller;
 2 
 3 
 4 import io.jsonwebtoken.Claims;
 5 import io.jsonwebtoken.Jwts;
 6 import org.apache.commons.lang.StringUtils;
 7 import org.springframework.web.bind.annotation.GetMapping;
 8 import org.springframework.web.bind.annotation.RestController;
 9 
10 import javax.servlet.http.HttpServletRequest;
11 import java.io.UnsupportedEncodingException;
12 import java.net.Authenticator;
13 
14 @RestController
15 public class UserController {
16 
17     @GetMapping("/user/me")
18     public Object getCurrentUser(Authenticator user , HttpServletRequest request) throws UnsupportedEncodingException {
19         String header = request.getHeader("Authorization");
20         String token = StringUtils.substringAfter(header,"bearer ");
21         Claims claims = Jwts.parser().setSigningKey("fanqi".getBytes("UTF-8")).parseClaimsJws(token).getBody();
22         String company = (String) claims.get("company");
23         System.out.println(company);
24         return user;
25     }
26 }
原文地址:https://www.cnblogs.com/fanqisoft/p/10669851.html