использоватьOAuth2иJWTосознатьЕдиный вход。Вот простой пример:
В этом примере показано, как OAuth2 и JWT работают вместе для реализации единого входа и авторизации. Используя Spring Cloud Security, мы можем легко реализовать эти функции и обеспечить мощную и гибкую поддержку безопасности. Демонстрирует, как использовать Spring Cloud Security и Spring Cloud Gateway для реализации единого входа на основе JWT и OAuth2:
Мы будем использовать Spring Security OAuth2 для создания нашего сервера авторизации. Вот некоторые ключевые конфигурации:
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client-id")
.secret("client-secret")
.authorizedGrantTypes("password")
.scopes("read", "write")
.accessTokenValiditySeconds(3600);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter());
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("signing-key");
return converter;
}
}
Мы настроили службу сведений о клиенте в памяти, используя имя пользователя и пароль в качестве типа авторизации. Мы также установили срок действия токена доступа на 3600 секунд. Мы также настроили AuthorizationServerEndpointsConfigurer для использования tokenStore и accessTokenConverter для обработки токенов JWT. Здесь мы используем закрытый ключ для подписи токена JWT, чтобы гарантировать, что он не был подделан.
Далее мы создадим ресурсы сервера, чтобы только прошедшие проверку подлинности пользователи могли получить доступ к защищенным конечным точкам API. Вот некоторые ключевые конфигурации:
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/**")
.authenticated();
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore());
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setVerifierKey("verifier-key");
return converter;
}
}
Эта конфигурация включит сервер ресурсов и настроит защищенные конечные точки API, для доступа к которым требуется проверка подлинности OAuth2. Мы также настроили bean-компонент tokenStore и bean-компонент jwtAccessTokenConverter для обработки токенов JWT. Здесь мы использовали открытый ключ для проверки токена JWT, который будет использоваться для проверки подписи токена JWT. Нам необходимо предоставить открытый ключ, который будет использоваться для проверки подписи JWT. При использовании JWT нам необходимо подписать токен JWT, чтобы гарантировать, что он не был подделан.
наконец,Создание шлюза,обрабатывать все входящие запросы,И при необходимости выполните аутентификацию OAuth2. Вот некоторые ключевые конфигурации:
@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class GatewaySecurityConfig {
@Autowired
private JwtTokenProvider jwtTokenProvider;
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
http.authorizeExchange()
.pathMatchers("/api/auth/**").permitAll()
.anyExchange().authenticated()
.and()
.oauth2ResourceServer().jwt()
.and()
.addFilterAt(jwtAuthenticationFilter(), SecurityWebFiltersOrder.AUTHENTICATION)
.csrf().disable();
return http.build();
}
@Bean
public ReactiveJwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withPublicKey(this.jwtTokenProvider.getPublicKey()).build();
}
@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter(jwtDecoder());
}
}
Здесь мы используем аннотацию @EnableWebFluxSecurity для включения Spring Security, а затем используем аннотацию @EnableReactiveMethodSecurity для включения безопасности на уровне метода. Мы используем компонент JwtTokenProvider, который содержит открытый и закрытый ключи для проверки и подписи токена JWT. Мы также создали bean-компонент SecurityWebFilterChain для настройки цепочки фильтров безопасности. Мы разрешаем анонимный доступ к конечной точке авторизации, все остальные конечные точки требуют аутентификации OAuth2. Мы использовали oauth2ResourceServer().jwt() для настройки проверки токена JWT, а затем добавили JwtAuthenticationFilter, который анализирует токен JWT и преобразует его в объект аутентификации Spring Security. Наконец, мы отключили защиту CSRF, поскольку она нам не нужна на шлюзе.
нам все еще нужно Создайте JwtTokenProvider. bean-компонент, который содержит открытый и закрытый ключи, используемые для проверки и подписи токенов JWT. Вот некоторые ключевые конфигурации:
@Component
public class JwtTokenProvider {
private final String publicKey;
private final String privateKey;
public JwtTokenProvider() throws Exception {
KeyPair keyPair = KeyPairUtils.generateKeyPair("RSA", 2048);
this.publicKey = new String(Base64.getEncoder().encode(keyPair.getPublic().getEncoded()));
this.privateKey = new String(Base64.getEncoder().encode(keyPair.getPrivate().getEncoded()));
}
public String getPublicKey() {
return publicKey;
}
public String getPrivateKey() {
return privateKey;
}
}
Здесь мы используем класс инструмента KeyPairUtils для создания пары ключей RSA и сохранения ее в компоненте JwtTokenProvider. Мы можем использовать этот компонент для получения открытого и закрытого ключей, которые затем можно использовать для проверки и подписи токена JWT.
наконец,Нам нужно разработать фильтр JwtAuthenticationFilter. bean, этот фильтр используется для анализа токенов JWT и преобразования их в Spring. Security Объект аутентификации. Вот некоторые ключевые конфигурации:
public class JwtAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private final ReactiveJwtDecoder jwtDecoder;
public JwtAuthenticationFilter(ReactiveJwtDecoder jwtDecoder) {
super("/api/**");
this.jwtDecoder = jwtDecoder;
}
@Override
public Mono<Authentication> attemptAuthentication(ServerWebExchange exchange) {
String authHeader = exchange.getRequest().getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String authToken = authHeader.substring(7);
return this.jwtDecoder.decode(authToken)
.map((jwt) -> new UsernamePasswordAuthenticationToken(jwt.getSubject(), null, jwt.getClaim("authorities").asList(String.class)))
.cast(Authentication.class)
.onErrorResume((ex) -> Mono.empty());
} else {
return Mono.empty();
}
}
}
Здесь мы создаем bean-компонент JwtAuthenticationFilter и наследуем AbstractAuthenticationProcessingFilter. Мы использовали компонент ReactiveJwtDecoder для анализа токена JWT и преобразования его в объект Spring Security Authentication. Мы реализовали метод tryAuthentication, который пытается проанализировать токен JWT и использовать его для создания нового объекта UsernamePasswordAuthenticationToken. Наконец, мы используем onErrorResume для обработки любых ошибок и возврата пустого объекта Mono.
Теперь мы можем создать наше приложение и убедиться, что JWT и OAuth2 правильно работают на шлюзе. Мы можем использовать следующую команду Curl для отправки токена JWT:
curl --request GET \
--url http://localhost:8080/api/users \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
Эта команда отправит шлюзу запрос GET, содержащий токен JWT, с использованием заголовка авторизации. Если все в порядке, шлюз перенаправит запрос в правильный микросервис и пройдет аутентификацию с использованием токена JWT. Если токен JWT недействителен или срок его действия истек, шлюз вернет ответ 401 Unauthorized.