TokenStore: Persistence interface for OAuth2 tokens

  • InMemoryTokenStore
  • JdbcTokenStore
  • JwtTokenStore

In addition, there will be a customized implementation of RedisTokenStore based on TokenStor’s features

A, InMemoryTokenStore

Summary 1.1.

This is the default implementation of OAuth2. This works well on a single service (that is, the concurrency is small and it does not take a backup in the event of a failure) and can be used on most projects. According to the name, it is stored in memory, after all, it exists in memory, not disk, easy to debug.

1.2. To achieve

Since InMemoryTokenStore is the default implementation of OAuth2, we don’t need to configure it, just call it.

1.3. Code invocation

@Autowired(required = false)
private TokenStore inMemoryTokenStore;
/** * endpoint (processing entry) */
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.tokenStore(inMemoryTokenStore); . }Copy the code

1.4. Test call access to obtain Token

Here is a small demo based on SpringBoot+Security, the relevant configuration is not too much in this article, focusing on TokenStore

  • Spring Security default authorization endpoint: Oauth/Token
  • The value is grant_type – >password

Second, the JdbcTokenStore

Summary 2.1.

This is a JDBC-based implementation where the Access tokens are saved to the database. In this way, token sharing can be implemented between multiple services.

2.2. To achieve

1). Since it is JDBC, you definitely need a data source. SpringBoot is used here, so a data source is configured. The required JAR dependencies are not covered.

spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/security? useUnicode=yes&characterEncoding=UTF-8 username: catalpaFlat password: catalpaFlatCopy the code

2). In addition to data sources, JDBC must have library tables, so OAuth2 gives the table structure by default

Drop table  if exists oauth_access_token;
create table oauth_access_token (
  create_time timestamp default now(),
  token_id VARCHAR(255),
  token BLOB,
  authentication_id VARCHAR(255),
  user_name VARCHAR(255),
  client_id VARCHAR(255),
  authentication BLOB,
  refresh_token VARCHAR(255))ENGINE=InnoDB DEFAULT CHARSET=utf8;

Drop table  if exists oauth_refresh_token;
create table oauth_refresh_token (
  create_time timestamp default now(),
  token_id VARCHAR(255),
  token BLOB.authentication BLOB
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Copy the code

And the JdbcTokenStore source code also has a lot of table operations:

3) the configuration JdbcTokenStore

@Autowired
private DataSource dataSource;
/** * JDBC token configuration */
@Bean
public TokenStore jdbcTokenStore(a) { Assert.state(dataSource ! =null."DataSource must be provided");
    return new JdbcTokenStore(dataSource);
}
Copy the code

2.3. Code invocation

@Autowired(required = false)
private TokenStore jdbcTokenStore;
/** * endpoint (processing entry) */
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.tokenStore(jdbcTokenStore); . }Copy the code

2.4. Test call access to obtain Token

Third, JwtTokenStore

Summary 3.1.

JWT Full name JSON Web Token This implementation does not matter how the storage is done (in memory or on disk) because it encodes the relevant information data in the token. JwtTokenStore does not hold any data, but it plays the same role as DefaultTokenServices in converting token values and authorization information.

3.2. To achieve

Since JWT stores the information in the token, it needs to consider its security. Therefore, OAuth2 provides JwtAccessTokenConverter implementation, adding jwtSigningKey to generate the secret key for signature, and only jwtSigningKey can get the information.

/** * JWT Token configuration, matchIfMissing = true **@author: CatalpaFlat * /
@Configuration
public class JwtTokenConfig {

   private final Logger logger = LoggerFactory.getLogger(JwtTokenConfig.class);
   @Value("${default.jwt.signing.key}")
   private String defaultJwtSigningKey;
   @Autowired
   private CustomYmlConfig customYmlConfig;

   public JwtTokenConfig(a) {logger.info("Loading JwtTokenConfig ..."); }@Bean
   public TokenStore jwtTokenStore(a) {
       return new JwtTokenStore(jwtAccessTokenConverter());
   }

   @Bean
   public JwtAccessTokenConverter jwtAccessTokenConverter(a) {
       JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
       String jwtSigningKey = customYmlConfig.getSecurity().getOauth2s().getOuter().getJwtSigningKey();
       Assert.state(StringUtils.isBlank(jwtSigningKey), "jwtSigningKey is not configured");
       / / the secret sign
       jwtAccessTokenConverter.setSigningKey(StringUtils.isBlank(jwtSigningKey) ? defaultJwtSigningKey : jwtSigningKey);
       returnjwtAccessTokenConverter; }}Copy the code

3.3. Code invocation

@Autowired(required = false)
private TokenStore jwtTokenStore;
@Autowired(required = false)
private JwtAccessTokenConverter jwtAccessTokenConverter;
/** * endpoint (processing entry) */
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.tokenStore(jwtTokenStore) .accessTokenConverter(jwtAccessTokenConverter); . }Copy the code

3.4. Test call access to obtain Token

Four, RedisTokenStore

Summary 4.1.

Since the TokenStore function is the OAuth2 token persistence interface, we are very careful about the use of memory in the actual development, and the storage to the database is allocated according to the needs of the project. So I wondered if redis could be used to store and persist our OAuth2 token. Took a sneak peek at OAuth2 and those that implement TokenStore and found a RedisTokenStore.

4.2. To achieve

Remember to configure Redis

@Autowired
private RedisConnectionFactory redisConnectionFactory;
/** * Redis token configuration */
@Bean
public TokenStore redisTokenStore(a) {
    return new RedisTokenStore(redisConnectionFactory);
}
Copy the code

4.3. Code invocation

@Autowired(required = false)
private TokenStore redisTokenStore;
/** * endpoint (processing entry) */
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.tokenStore(redisTokenStore); . }Copy the code

4.4. Test call access to obtain Token