问题
In my design I have an API gateway (spring cloud api gateway), authorization server (Oauth2) and a resource server (microservice). (I have also a CAS server but now it can be ignored for simplicity)
I just want to use API gateway to redirect client requests.
- If the user is not authenticated, request should be sent to authorization server and after authentication and authorization process is finished, authorization server should return JSESSION and JWT in access_token header. After that API gateway should return JSESSION AND JWT to client.
- If the user is authenticated request should be sent to resource server.
So API gateway would be stateless and used just for redirection of requests. But when I successfully login, JSESSION and SESSION cookies are set and JWT is not sent to client. (As far as understand from logs, API Gateway has JWT but instead of simply sending it to client, stores it with SESSION key and send SESSION key)
How can I make my API gateway stateless and send JWT in access_token header to client?
Here is my code:
Authorization Server:
@EnableWebSecurity
@Order(1)
public class MySecurityConfigurationDev extends WebSecurityConfigurerAdapter {
@Bean
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login/**", "/oauth/**", "/userinfo")
.permitAll()
.and()
.formLogin().permitAll().and()
.authorizeRequests().anyRequest().authenticated();
http.csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("{noop}pass").roles("ADMIN");
}
}
@Configuration
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Bean
public KeyPair keyPair() {
return new KeyStoreKeyFactory(new ClassPathResource("keystore.jks"), "mystorepass".toCharArray()).getKeyPair("mytestkey");
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setKeyPair(keyPair());
return converter;
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager).accessTokenConverter(accessTokenConverter());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()").
checkTokenAccess("permitAll()").
allowFormAuthenticationForClients();
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient("first-client").secret("{noop}noonewilleverguess")
.authorities("ADMIN")
.authorizedGrantTypes("client_credentials", "password", "authorization_code", "refresh_token")
.scopes("custom_mod")
.accessTokenValiditySeconds(60*30)
.refreshTokenValiditySeconds(60*60)
.autoApprove(true)
.redirectUris("http://localhost:8085/login/oauth2/code/login-client");
}
}
API Gateway:
@EnableWebFluxSecurity
public class MySecurityConfiguration {
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http, ReactiveClientRegistrationRepository clientRegistrationRepository) {
http.authorizeExchange().anyExchange().authenticated().and().oauth2Login();
return http.build();
}
}
logging:
level:
root: TRACE
org.springframework.cloud.gateway: DEBUG
reactor.netty.http.client: DEBUG
com.netflix.discovery.DiscoveryClient: error
org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator: error
com.netflix.discovery.shared.resolver.aws.ConfigClusterResolver: error
server:
port: 8085
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8010/eureka
spring:
application:
name: gateway-server
cloud:
gateway:
default-filters:
- RemoveRequestHeader=Cookie
- TokenRelay=
routes:
- id: user_route
predicates:
- Path=/gateway-user/**
filters:
- RewritePath=/gateway-user/(?<segment>.*), /user/$\{segment}
- RemoveRequestHeader=Cookie
- name: Hystrix
args:
name: fallbackCommand
fallbackUri: forward:/fallback/error
uri: "lb://USER-RESOURCE-SERVER"
- id: address_route
predicates:
- Path=/gateway-address/**
filters:
- RewritePath=/gateway-address/(?<segment>.*), /address/$\{segment}
uri: "lb://ADDRESS-RESOURCE-SERVER"
security:
oauth2:
client:
registration:
login-client:
provider: uaa
client-id: first-client
client-secret: noonewilleverguess
authorization-grant-type: authorization_code
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
scope: custom_mod
provider:
uaa:
authorization-uri: http://localhost:8094/oauth/authorize
token-uri: http://localhost:8094/oauth/token
user-info-uri: http://localhost:8094/userinfo
user-name-attribute: user_name
user-info-authentication-method: form
**Spring Boot version is 2.1.6-RELEASE for both servers.
来源:https://stackoverflow.com/questions/60669768/how-to-make-api-gateway-stateless-for-authentication-authorization-process-using