Подробное объяснение реализации Spring Security TokenStore 3+1

Spring Безопасность
Подробное объяснение реализации Spring Security TokenStore 3+1

TokenStore: интерфейс сохраняемости для токенов OAuth2 (для интерфейса сохраняемости токенов OAuth2).
официальная документация
Существует три реализации TokenStore по умолчанию:

  • InMemoryTokenStore
  • JdbcTokenStore
  • JwtTokenStore

spring 关于tokenstore的文档

Кроме того, под особенности TokenStor будет настроена еще одна реализация — RedisTokenStore.

1. InMemoryTokenStore

1.1. Обзор

Это реализация OAuth2 по умолчанию. Он может показать хорошие результаты для отдельной службы (то есть параллелизм невелик, и его резервная копия не будет создаваться в случае сбоя), и этот метод можно использовать в большинстве проектов. Судя по названию, он хранится в памяти, ведь он существует в памяти, а не на диске, и отлаживать его несложно.

1.2. Реализация

Поскольку InMemoryTokenStore является реализацией OAuth2 по умолчанию, нам не нужно его настраивать, просто вызовите его напрямую.

InMemoryTokenStore 实现

1.3. Вызов кода

@Autowired(required = false)
private TokenStore inMemoryTokenStore;
/**
 * 端点(处理入口)
 */
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
   endpoints.tokenStore(inMemoryTokenStore);
   ....
}

1.4. Доступ к тестовому звонку для получения токена

Вот небольшая демонстрация, основанная на SpringBoot+Security, и соответствующая конфигурация не будет слишком много упоминаться в этой статье, сосредоточив внимание на TokenStore.

  • Spring Security Конечная точка аутентификации авторизации по умолчанию: oauth/token
  • Используется здесь: grant_type—>режим пароля

InMemoryTokenStore 测试

2. JdbcTokenStore

2.1. Обзор

Это реализация на основе JDBC, и токен (токен доступа) будет сохранен в базе данных. Таким образом, совместное использование токенов может быть достигнуто между несколькими службами.

2.2. Реализация

1). Поскольку это JDBC, ему нужен источник данных. Здесь используется SpringBoot, поэтому настроен источник данных. Не так много, чтобы сказать о необходимых зависимостях jar.

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

2).Помимо источника данных,тогда у jdbc должна быть библиотечная таблица,поэтому OAuth2 отдает структуру таблицы по умолчанию

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;

А операций над таблицей в исходном коде JdbcTokenStore много:

JdbcTokenStore 源码

3).Настройте JdbcTokenStore

@Autowired
private DataSource dataSource;
/**
 * jdbc token 配置
 */
@Bean
public TokenStore jdbcTokenStore() {
    Assert.state(dataSource != null, "DataSource must be provided");
    return new JdbcTokenStore(dataSource);
}

2.3. Вызов кода

@Autowired(required = false)
private TokenStore jdbcTokenStore;
/**
 * 端点(处理入口)
 */
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
   endpoints.tokenStore(jdbcTokenStore);
   ....
}

2.4. Доступ к тестовому звонку для получения токена

JdbcTokenStore 测试
JdbcTokenStore 测试
JdbcTokenStore 测试
JdbcTokenStore 测试

3. JwttokenStore.

3.1 Обзор

Полное имя jwt — JSON Web Token. Этой реализации не важно, как она хранится (в памяти или на диске), потому что она может кодировать соответствующие информационные данные в маркере. JwtTokenStore не хранит никаких данных, но играет ту же роль, что и DefaultTokenServices, в преобразовании значений токенов и информации об авторизации.

3.2. Реализация

Поскольку jwt хранит информацию в токенах, необходимо учитывать его безопасность, поэтому OAuth2 предоставляет реализацию JwtAccessTokenConverter, добавляя jwtSigningKey для генерации секретного ключа для подписи, и только jwtSigningKey может получить информацию.

/**
* jwt Token 配置, 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() {logger.info("Loading JwtTokenConfig ...");}

   @Bean
   public TokenStore jwtTokenStore() {
       return new JwtTokenStore(jwtAccessTokenConverter());
   }

   @Bean
   public JwtAccessTokenConverter jwtAccessTokenConverter() {
       JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
       String jwtSigningKey = customYmlConfig.getSecurity().getOauth2s().getOuter().getJwtSigningKey();
       Assert.state(StringUtils.isBlank(jwtSigningKey), "jwtSigningKey is not configured");
       //秘签
       jwtAccessTokenConverter.setSigningKey(StringUtils.isBlank(jwtSigningKey) ? defaultJwtSigningKey : jwtSigningKey);
       return jwtAccessTokenConverter;
   }
}

3.3. Вызов кода

@Autowired(required = false)
private TokenStore jwtTokenStore;
@Autowired(required = false)
private JwtAccessTokenConverter jwtAccessTokenConverter;
/**
 * 端点(处理入口)
 */
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
   endpoints.tokenStore(jwtTokenStore)
   .accessTokenConverter(jwtAccessTokenConverter);
   ....
}

3.4. Доступ к тестовому звонку для получения токена

JwtTokenStore 测试
JwtTokenStore 测试

4. RedisTokenStore

4.1 Обзор

Поскольку функция TokenStore заключается в сохранении интерфейса для токенов OAuth2, в фактической разработке мы осторожно относимся к использованию памяти, а хранилище в базе данных также настраивается в соответствии с требованиями проекта. Поэтому я подумал, можем ли мы использовать Redis для хранения и сохранения наших токенов OAuth2. Взглянув на OAuth2 и тех, кто реализует TokenStore, я нашел RedisTokenStore.

RedisTokenStore 概述

4.2. Реализация

Не забудьте настроить Redis

@Autowired
private RedisConnectionFactory redisConnectionFactory;
/**
 * redis token 配置
 */
@Bean
public TokenStore redisTokenStore() {
    return new RedisTokenStore(redisConnectionFactory);
}

4.3. Вызов кода

@Autowired(required = false)
private TokenStore redisTokenStore;
/**
 * 端点(处理入口)
 */
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
   endpoints.tokenStore(redisTokenStore);
   ....
}

4.4. Доступ к тестовому звонку для получения токена

RedisTokenStore 测试
RedisTokenStore 测试