How to make API Gateway Stateless for Authentication/Authorization Process Using Oauth2?

北城以北 提交于 2020-04-30 05:48:05

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!