相关文章推荐
傻傻的警车  ·  202101 ...·  2 年前    · 
乖乖的泡面  ·  mysql 视图中使用变量 ...·  2 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I am developing authentication and authorization in an environment where I use Spring Cloud Gateway Webflux + OAuth 2.0 the structure to achieve is the following:

As Authorization Server I have my own OAuth server that contains the /login page where I perform the authentication and it is also in charge of generating JWT and as Resource Server I have a WebFlux module that is also in charge of being the Gateway.

The Resource Server configuration is as follows:

application.yml

spring:
  application:
    name: spring-boot-gateway
  security:
    oauth2:
      resourceserver:
          issuer-uri: http://adp-auth-provider/auth/oauth/token
      client:
        registration:
          oauth:
            client-name: oauth
            client-id: first-client
            client-secret: xxxxxx
            provider: adp-auth-provider
            authorization-grant-type: authorization_code
            redirect-uri: /login
            scope: read
        provider:
          adp-auth-provider:
            authorization-uri: /auth/oauth/authorize
            token-uri: http://adp-auth-provider/auth/oauth/token
            user-info-uri: http://adp-auth-provider/userinfo
            jwt-set-uri: http://adp-auth-provider/token_keys

WebFluxSecurityConfig.java

    @Configuration(proxyBeanMethods = false)
    @EnableWebFluxSecurity
    @EnableReactiveMethodSecurity
    public class WebFluxSecurityConfig {
        @Bean
        public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
            return http
                    .httpBasic().disable()
                    .csrf().disable()
                    .authorizeExchange(exchanges -> exchanges
                            .pathMatchers(HttpMethod.GET, "/oauth2/authorization/**",
                                    "/actuator",
                                    "/actuator/**",
                                    "/auth/login",
                                    "/login")
                            .permitAll()
                            .anyExchange()
                                    .authenticated()
                    .oauth2Login()
                    .and()
                    .build();

SpringGatewayApplication.java

@SpringBootApplication
public class SpringGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringGatewayApplication.class, args);

When I type http://localhost in the browser, it redirects perfectly to the OAuth /login page, but when I enter my credentials it redirects me to the next page:

The requests appear to have been the right ones:

Does anyone know why I am not redirected to the index once I have logged in correctly? It stays on that page and if I click on oauth it redirects me to the same page again.

**EDIT:

Setting redirect-uri to the default "{baseUrl}/login/oauth2/code/{registrationId}" displays the following error:

2022-01-18 12:12:15.852 ERROR 2836 --- [ctor-http-nio-6] a.w.r.e.AbstractErrorWebExceptionHandler : [477242e5-1]  500 Server Error for HTTP GET "/login/oauth2/code/oauth?code=nTCRNi&state=Ub8jQjbp1baxhgsxcpNULMMHoV8z42bQsp62iL2jNV8%3D"
java.lang.IllegalStateException: No provider found for class org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeAuthenticationToken
    at org.springframework.security.web.server.authentication.AuthenticationWebFilter.lambda$authenticate$6(AuthenticationWebFilter.java:123) ~[spring-security-web-5.6.0.jar:5.6.0]
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
    *__checkpoint ⇢ org.springframework.security.oauth2.client.web.server.authentication.OAuth2LoginAuthenticationWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ org.springframework.security.oauth2.client.web.server.OAuth2AuthorizationRequestRedirectWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ org.springframework.security.web.server.context.ReactorContextWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ org.springframework.security.web.server.header.HttpHeaderWriterWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ org.springframework.security.config.web.server.ServerHttpSecurity$ServerWebExchangeReactorContextWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ org.springframework.security.web.server.WebFilterChainProxy [DefaultWebFilterChain]
    *__checkpoint ⇢ org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ HTTP GET "/login/oauth2/code/oauth?code=nTCRNi&state=Ub8jQjbp1baxhgsxcpNULMMHoV8z42bQsp62iL2jNV8%3D" [ExceptionHandlingWebHandler]
Original Stack Trace:
        at org.springframework.security.web.server.authentication.AuthenticationWebFilter.lambda$authenticate$6(AuthenticationWebFilter.java:123) ~[spring-security-web-5.6.0.jar:5.6.0]
        at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:44) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.core.publisher.Mono.subscribe(Mono.java:4400) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:82) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.core.publisher.FluxHide$SuppressFuseableSubscriber.onComplete(FluxHide.java:147) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.core.publisher.MonoNext$NextSubscriber.onComplete(MonoNext.java:102) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:367) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.innerComplete(FluxConcatMap.java:296) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onComplete(FluxConcatMap.java:885) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.core.publisher.MonoFlatMap$FlatMapMain.secondComplete(MonoFlatMap.java:196) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.core.publisher.MonoFlatMap$FlatMapInner.onComplete(MonoFlatMap.java:268) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:142) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2058) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2058) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onComplete(FluxMapFuseable.java:150) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.core.publisher.MonoFlatMap$FlatMapMain.secondComplete(MonoFlatMap.java:196) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.core.publisher.MonoFlatMap$FlatMapInner.onComplete(MonoFlatMap.java:268) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2058) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.core.publisher.MonoNext$NextSubscriber.onComplete(MonoNext.java:102) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:142) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:142) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:260) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:142) ~[reactor-core-3.4.12.jar:3.4.12]
        at reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:400) ~[reactor-netty-core-1.0.13.jar:1.0.13]
        at reactor.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:419) ~[reactor-netty-core-1.0.13.jar:1.0.13]
        at reactor.netty.channel.ChannelOperations.terminate(ChannelOperations.java:473) ~[reactor-netty-core-1.0.13.jar:1.0.13]
        at reactor.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:702) ~[reactor-netty-http-1.0.13.jar:1.0.13]
        at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:93) ~[reactor-netty-core-1.0.13.jar:1.0.13]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103) ~[netty-codec-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324) ~[netty-codec-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296) ~[netty-codec-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986) ~[netty-common-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.70.Final.jar:4.1.70.Final]
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.70.Final.jar:4.1.70.Final]
        at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]

The application.yml now looks like this:

spring:
  application:
    name: spring-boot-gateway
  security:
    oauth2:
      resourceserver:
          issuer-uri: http://localhost/auth/oauth/token
      client:
        registration:
          oauth:
            client-name: oauth
            client-id: first-client
            client-secret: xxxx
            provider: adp-auth-provider
            authorization-grant-type: authorization_code
            redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}'
            scope: read
        provider:
          adp-auth-provider:
            authorization-uri: http://localhost/auth/oauth/authorize
            token-uri: http://localhost/auth/oauth/token
            user-info-uri: http://localhost/auth/me
            user-name-attribute: sub
                Does this answer your question? Spring Oauth2 client with Google provider keep asking for authentication
– Eleftheria Stein-Kousathana
                Jan 14, 2022 at 15:40
                I'm afraid not, for ServerHttpSecurity I can't find a defaultSuccessUrl, may it be another one?
– Pablo Aragonés
                Jan 14, 2022 at 21:45

You have specified a redirect-uri for your client of /login. The page that says "Login with OAuth 2.0" is an auto-generated login page that Spring Security makes available by default under the /login endpoint. I don't think you intended to redirect there, but you currently have configured your client to do so.

The docs for OAuth 2.0 Login with WebFlux (Reactive) have recently been rewritten to align with the Servlet version, and are worth reading in their entirety.

Read the section of the docs on the Redirection Endpoint. Until you have a basic flow working, I'd recommend setting your redirect-uri to the default value of "{baseUrl}/login/oauth2/code/{registrationId}". Once things work, you can begin exploring how to customize this value. As the docs state, keep in mind that changing your redirect-uri property for a client also requires customizing the Redirection Endpoint in Spring Security to match.

If you also wish to customize the default Login Page, see the previous section of the docs, OAuth 2.0 Login Page.

Thank you very much for the reply and for the information, I will check everything well. Anyway, I previously set the redirect-uri as {baseUrl}/login/oauth2/code/{registrationId}" but it gave me a 500 error and that's why I changed the configuration.I'm going to edit the question to make that clear and in case you can help me with it. Thank you very much!! – Pablo Aragonés Jan 18, 2022 at 11:17

The problem was occurring because the default authentication manager wasn't working for me, I had to implement one specifically for my problem.

@Configuration(proxyBeanMethods = false) @EnableWebFluxSecurity @EnableReactiveMethodSecurity public class WebFluxSecurityConfig { @Bean public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http, AuthenticationManager authenticationManager) { return http .httpBasic().disable() .csrf().disable() .authorizeExchange(exchanges -> exchanges .pathMatchers(HttpMethod.GET, "/oauth2/authorization/**", "/actuator", "/actuator/**", "/auth/login", "/login/**") .permitAll() .anyExchange() .authenticated() .oauth2Login() .authenticationManager(authenticationManager) .and() .build();

I also had to modify the redirect-uri and leave it as '/login/oauth2/code/{registrationId}'.

spring:
  application:
    name: spring-boot-gateway
  security:
    oauth2:
      resourceserver:
          issuer-uri: http://127.0.0.1/auth/oauth/token
      client:
        registration:
          oauth:
            client-name: oauth
            client-id: first-client
            client-secret: xxxxx
            provider: adp-auth-provider
            authorization-grant-type: authorization_code
            redirect-uri: '/login/oauth2/code/{registrationId}'
            scope: read
        provider:
          adp-auth-provider:
            authorization-uri: /auth/oauth/authorize
            token-uri: /auth/oauth/token
            user-info-uri: /auth/me
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.