通过Cloud Gateway的Oauth2客户端登录提供了400个无效的客户端注册ID

时间:2019-10-20 07:20:56

标签: spring-cloud spring-security-oauth2 spring-webflux api-gateway

我有一个Spring授权/资源服务器,用于管理Webflux Oauth2客户端的授权。单独运行就可以了。当我添加Spring Cloud Gateway并通过网关访问Webflux时,我看到授权服务器验证了用户,并且Webflux返回302,但是在网关上,我得到了400个“无效的客户端注册ID”。

授权/资源服务器为;

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.9.RELEASE</version>
        <relativePath/>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.oauth.boot</groupId>
            <artifactId>spring-security-oauth2-autoconfigure</artifactId>
            <version>2.1.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-jose</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
     </dependencies>

首发;

@SpringBootApplication
@EnableAuthorizationServer
@EnableResourceServer
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

属性;

server:
  port: 8889

服务器配置;


@Configuration
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter  {

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore());
    }

    @Bean
    public TokenStore tokenStore() {
        return new InMemoryTokenStore();
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
    }

    @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory()
                .withClient("myClientId2")
                .secret(passwordEncoder.encode("mySecret2"))
                .authorizedGrantTypes("authorization_code")
                .scopes("all")
                .autoApprove(true)
                .redirectUris("http://localhost:8083/login/oauth2/code/myAppTwo") 
                .and()
                .withClient("myGatewayId")
                .secret(passwordEncoder.encode("myGatewaySecret"))
                .authorizedGrantTypes("authorization_code")
                .scopes("all")
                .autoApprove(true)
                .redirectUris("http://localhost:8888/login/oauth2/code/gateway") 
                ;
        }
}

安全性

@Configuration
@Order(1)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .requestMatchers()
            .antMatchers("/login", "/oauth/authorize")
            .and().authorizeRequests().anyRequest().authenticated()
            .and().formLogin().permitAll();
    }

    @Override

    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("x").password(passwordEncoder().encode("123"))
            .roles("USER");
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

用户响应;

@RestController
public class UserController {

        @GetMapping("/user")
        public Principal user(Principal principal) {
            System.err.println(principal);
            return principal;
        }

Webflux是;

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.9.RELEASE</version>
        <relativePath/>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-client</artifactId>
        </dependency>
    </dependencies>

属性;

server:
  port: 8083   
spring:
  security:
    oauth2:
      client:
       registration:
         myAppTwo:
           client-name: Test8082
           client-id: myClientId2
           client-secret: mySecret2
           authorization-grant-type: authorization_code
           redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
       provider:
         myAppTwo:
           authorization-uri: http://localhost:8889/oauth/authorize
           token-uri: http://localhost:8889/oauth/token
           user-info-uri: http://localhost:8889/user
           user-name-attribute: name

Webflux端点;

@RestController
public class Controller {
    @GetMapping(value = "/test3")
    Mono<OAuth2User> getTest3(@AuthenticationPrincipal Mono<OAuth2User> ouser) {
        System.err.println("o =" + ouser);
        return ouser;
    }
}

通过Chrome运行http://localhost:8083/test3,将我带到授权服务器上的登录页面,然后输入凭据,然后上面的URL返回预期的响应。

当我添加网关时;

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.9.RELEASE</version>
        <relativePath/>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-security</artifactId>
        </dependency>
                <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-thymeleaf</artifactId>
            </dependency>
    </dependencies>

具有属性;

server:
  port: 8888   
spring:
  autoconfigure:
    # TODO: remove when fixed https://github.com/spring-projects/spring-security/issues/17949
    # Without this line, Gateway tries to log in using it's own security, rather than deferring to OAuth2
    exclude: org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration
  cloud:
    gateway:
      routes:
      - id: oauth
        predicates:
          - Path=/oauth2/**
        uri: http://localhost:8889
        filters:
          - TokenRelay=
          - RemoveRequestHeader=Cookie
      - id: route2
        predicates:
          - Path=/2/**
        uri: http://localhost:8083
        filters:
          - RewritePath=/2/(?<myPath>.*), /$\{myPath} 
          - TokenRelay=
          - RemoveRequestHeader=Cookie
  security:
    oauth2:
      client:
        registration:
          gateway:
            client-id: myGatewayId
            client-secret: myGatewaySecret
            authorization-grant-type: authorization_code
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
            provider: gateway
        provider:
          gateway:
            authorization-uri: http://localhost:8889/oauth/authorize
            token-uri: http://localhost:8889/oauth/token
            user-info-uri: http://localhost:8889/user
            user-name-attribute: name 
            jwk-set-uri: http://localhost:8889/oauth/token_key

现在,如果我尝试使用http://localhost:8888/2/test3,我仍将被重定向到登录名。授权服务器上的toString记录凭据,Webflux仍然提供302,但是网关执行以下操作;

Route matched: route2
Mapping [Exchange: GET http://localhost:8888/2/test3] to Route{id='route2', uri=http://localhost:8083, order=0, predicate=Paths: [/2/**], match trailing slash: true, gatewayFilters=[[[RewritePath /2/(?<myPath>.*) = '/${myPath}'], order = 1], [org.springframework.cloud.security.oauth2.gateway.TokenRelayGatewayFilterFactory$$Lambda$666/1724736027@4b96b22, order = 2], [[RemoveRequestHeader name = 'Cookie'], order = 3]]}
[98bb6dad] Mapped to org.springframework.cloud.gateway.handler.FilteringWebHandler@6fa90b79
Sorted gatewayFilterFactories: [[GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.RemoveCachedBodyFilter@1894593a}, order = -2147483648], [GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter@b835727}, order = -2147482648], [GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.NettyWriteResponseFilter@7fd26ad8}, order = -1], [GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.ForwardPathFilter@7cea0110}, order = 0], [GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.GatewayMetricsFilter@5527b211}, order = 0], [[RewritePath /2/(?<myPath>.*) = '/${myPath}'], order = 1], [org.springframework.cloud.security.oauth2.gateway.TokenRelayGatewayFilterFactory$$Lambda$666/1724736027@4b96b22, order = 2], [[RemoveRequestHeader name = 'Cookie'], order = 3], [GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter@14b0e127}, order = 10000], [GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.config.GatewayNoLoadBalancerClientAutoConfiguration$NoLoadBalancerClientFilter@54cf7c6a}, order = 10100], [GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.WebsocketRoutingFilter@468dda3e}, order = 2147483646], [GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.NettyRoutingFilter@3d37203b}, order = 2147483647], [GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.ForwardRoutingFilter@10823d72}, order = 2147483647]]
"GET /2/test3 HTTP/1.1" 302 0 8888 8 ms
Resolved [ResponseStatusException: 400 BAD_REQUEST "Invalid client registration id"] for HTTP GET /oauth2/authorization/myAppTwo
Writing "<html><body><h1>Whitelabel Error Page</h1><p>This application has no configured error view, so you  (truncated)...
"GET /oauth2/authorization/myAppTwo HTTP/1.1" 400 312 8888 2 ms
"GET /favicon.ico HTTP/1.1" 302 0 8888 2 ms
"GET /oauth2/authorization/gateway HTTP/1.1" 302 0 8888 2 ms
Writing form fields [grant_type, code, redirect_uri] (content masked)
Decoded [{access_token=2c14f1e7-5d95-4fed-be95-2d8518d1fb48, token_type=bearer, expires_in=40912, scope=all}]
Decoded [{authorities=[{authority=ROLE_USER}], details={remoteAddress=127.0.0.1, sessionId=null, tokenValue=2 (truncated)...]
"GET /login/oauth2/code/gateway?code=fGdiyz&state=ZynriL0UtU37b4rMfDHM7JheNYYo0UnZQvgu4U2kWwQ%3D HTTP/1.1" 302 0 8888 82 ms
"GET / HTTP/1.1" 200 3348 8888 5 ms

通过相同浏览器会话,如果我尝试直接URL http://localhost:8083/test,它将正确响应(即,我已登录并且8083具有我的凭据)。

我通过调试看到DefaultServerOAuth2AuthorizationRequestResolver.findByRegistrationId首先检查gateway的重定向并通过。但是,它尝试进行myAppTwo重定向的第二遍尝试并失败,该重定向未定义网关的YML,我认为不应该这样做。删除路由oauth似乎没有任何影响。我从没见过那条路被击中。

那么如何使网关重定向到端口8083上的myAppTwo

更新,当我使用KeyCloak而不是我自己的AuthorizationServer / ResourceServer时,会遇到相同的问题。

0 个答案:

没有答案