Я использую k8s для масштабирования сервера авторизации (2 реплики), когда я получаю токен с авторизацииServer1 и проверяю токен на сервере ресурсов путем самоанализа ответа конечной точки 401, но авторизацияServer2 получает успех.
Как с этим справиться или какое-то руководство по правильному пути для масштабируемого сервера авторизации
открытый класс AuthServer {
@Autowired
private OAuthConfig authConfig;
@Autowired
PasswordEncoder passwordEncoder;
@Value("${auth.server.issuer}")
private String issuerAuth;
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(Customizer.withDefaults()); // Enable OpenID Connect 1.0
return http.build();
}
@Bean
public TokenSettings tokenSettings() {
// @formatter:off
return TokenSettings.builder()
.accessTokenTimeToLive(Duration.ofMinutes(30L))
.build();
// @formatter:on
}
@Bean
public RegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate) {
JdbcRegisteredClientRepository registeredClientRepository = new JdbcRegisteredClientRepository(jdbcTemplate);
RegisteredClient registeredClient = registeredClientRepository.findByClientId(authConfig.getClientId());
if (Objects.isNull(registeredClient)) {
registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId(authConfig.getClientId())
.clientSecret(passwordEncoder.encode(authConfig.getClientSecret()))
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.tokenSettings(tokenSettings())
.scope("read")
.build();
}
registeredClientRepository.save(registeredClient);
return registeredClientRepository;
}
@Bean
public JWKSource<SecurityContext> jwkSource() throws Exception {
KeyPair keyPair = generateRsaKey();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
RSAKey rsaKey = new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID("key-id")
.build();
JWKSet jwkSet = new JWKSet(rsaKey);
System.out.println(jwkSet);
return new ImmutableJWKSet<>(jwkSet);
}
private static KeyPair generateRsaKey() {
KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(3072);
keyPair = keyPairGenerator.generateKeyPair();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
return keyPair;
}
@Bean
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
@Bean
public AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder().issuer(issuerAuth).build();
}
@Bean
public OAuth2TokenCustomizer<JwtEncodingContext> jwtEncodingContextOAuth2TokenCustomizer() {
return (context -> {
Authentication authentication = context.getPrincipal();
if (authentication.getPrincipal() instanceof String) {
OAuth2AuthorizationGrantAuthenticationToken tok = (OAuth2AuthorizationGrantAuthenticationToken) context.getAuthorizationGrant();
context.getClaims().claim("merchantCenterId", tok.getAdditionalParameters().get("merchantCenterId"));
context.getClaims().claim("roleId", tok.getAdditionalParameters().get("roleId"));
context.getClaims().claim("username", tok.getAdditionalParameters().get("user_name"));
}
});
}
}
Я просто повторю то, что Маркус сказал в комментариях, а именно то, что вам нужно будет сохранять авторизацию и согласие на авторизацию в базе данных, такой как реализация JDBC OAuth2AuthorizationService и OAuth2AuthorizationConsentService или руководство Как -to: реализация основных сервисов с помощью JPA демонстрирует. Или, если вы выберете, вы можете хранить их в хранилище данных NoSQL, таком как Redis, но для этого нет готовой реализации.
Обратите внимание, что вы также должны хранить свои сеансы и ключи в базе данных или хранилище данных NoSQL (например, Redis). Spring Session отлично подходит для выгрузки сессий в хранилище данных и может быть легко добавлен в ваше приложение Spring Boot, но хранение ключей вне JVM еще не продемонстрировано.
В связи с этим я рекомендую вам ознакомиться с выступлением Роба Винча на Spring I/O от мая 2023 года о Enterprise Security with Spring Authorization Server . Ближе к концу его доклад посвящен подключению стратегии ротации ключей, и он упоминает, что вы можете легко заменить реализацию в памяти из его примера репозитория на реализацию, поддерживаемую базой данных (например, с использованием Spring Data JDBC или JPA).
Это советы, которые вам понадобятся для масштабирования вашего сервера аутентификации на основе k8s в производственной среде.
Вы должны сохранять авторизации где-то в общем доступе, например в базе данных, по умолчанию SAS хранит авторизации в памяти. Взгляните на docs.spring.io/spring-authorization-server/docs/current/…