所有端点在我的Spring Boot Project中添加ResourceServer时,将返回ControlRETEST中的401/403

发布于 2025-02-12 06:40:02 字数 6000 浏览 1 评论 0 原文

如今,我们将将自定义JWT过滤器迁移到Auth0 IDP。

我在此项目中使用了Spring 2.7.1,WebFlux/Kotlin Coroutines。我创建

顺便说一句,我已经维护了一个webMVC版本到demo suring security oauth2和oauth0(更新为spring 2.7.1),其中

当我添加 org.springframework.boot:spring-boot-starter-oauth2-resource-server 在我们的项目dep中,以在我们的后端API中启用OAuth2 Resource Server支持。

但是现在,所有API端点都受到保护,并返回401或403。

我的安全配置都是这样。

@Bean
fun springWebFilterChain(http: ServerHttpSecurity, reactiveJwtDecoder: ReactiveJwtDecoder): SecurityWebFilterChain =
http {

    csrf { disable() }
    httpBasic { disable() }
    formLogin { disable() }
    logout { disable() }

    // enable OAuth2 resource server support
    oauth2ResourceServer { jwt { jwtDecoder = reactiveJwtDecoder } }
    exceptionHandling {
        authenticationEntryPoint = problemSupport
        accessDeniedHandler = problemSupport
    }
    authorizeExchange {
        authorize(pathMatchers(GET, "/v1/me"), authenticated)
        authorize(anyExchange, permitAll)
    }
}

测试代码就是这样,检查完整代码(测试是从其他项目移植的,我尚未添加JWT模拟)。

@Test
fun `get all posts`() = runTest {
    coEvery { posts.findAll() } returns flowOf(
        Post(
            id = UUID.randomUUID(),
            title = "test title",
            content = "test content"
        )
    )

    client.get()
        .uri("/posts").accept(MediaType.APPLICATION_JSON)
        .exchange()
        .expectStatus().isOk
        .expectBodyList(Post::class.java).hasSize(1)

    coVerify(exactly = 1) { posts.findAll() }
}

获取所有帖子端点设置为许可证,在运行 curl http:// localhost:8080/posts 命令中强>它运行良好,并在控制台中打印所有帖子。

运行 get /posts < /code>端点的测试时。我从控制台中获得了以下信息。

2022-07-01 12:45:27.021 DEBUG 14132 --- [           main] o.s.w.r.f.client.ExchangeFunctions       : [6144e499] HTTP GET /posts
2022-07-01 12:45:27.069 DEBUG 14132 --- [     parallel-1] o.s.w.s.adapter.HttpWebHandlerAdapter    : [26193fe] HTTP GET "/posts"
2022-07-01 12:45:27.108 DEBUG 14132 --- [     parallel-1] .s.s.w.s.u.m.AndServerWebExchangeMatcher : Trying to match using org.springframework.security.web.server.csrf.CsrfWebFilter$DefaultRequireCsrfProtectionMatcher@6fc32403
2022-07-01 12:45:27.110 DEBUG 14132 --- [     parallel-1] .s.s.w.s.u.m.AndServerWebExchangeMatcher : Did not match
2022-07-01 12:45:27.146 DEBUG 14132 --- [     parallel-2] o.s.w.s.s.DefaultWebSessionManager       : Created new WebSession.
2022-07-01 12:45:27.151 DEBUG 14132 --- [     parallel-2] o.s.s.w.s.u.m.OrServerWebExchangeMatcher : Trying to match using PathMatcherServerWebExchangeMatcher{pattern='/logout', method=POST}
2022-07-01 12:45:27.151 DEBUG 14132 --- [     parallel-2] athPatternParserServerWebExchangeMatcher : Request 'GET /posts' doesn't match 'POST /logout'
2022-07-01 12:45:27.152 DEBUG 14132 --- [     parallel-2] o.s.s.w.s.u.m.OrServerWebExchangeMatcher : No matches found
2022-07-01 12:45:27.156 DEBUG 14132 --- [     parallel-2] a.DelegatingReactiveAuthorizationManager : Checking authorization on '/posts' using org.springframework.security.authorization.AuthenticatedReactiveAuthorizationManager@66bdd968
2022-07-01 12:45:27.159 DEBUG 14132 --- [     parallel-2] ebSessionServerSecurityContextRepository : No SecurityContext found in WebSession: 'org.springframework.web.server.session.InMemoryWebSessionStore$InMemoryWebSession@529dcf30'
2022-07-01 12:45:27.160 DEBUG 14132 --- [     parallel-2] o.s.s.w.s.a.AuthorizationWebFilter       : Authorization failed: Access Denied
2022-07-01 12:45:27.174 DEBUG 14132 --- [     parallel-2] ebSessionServerSecurityContextRepository : No SecurityContext found in WebSession: 'org.springframework.web.server.session.InMemoryWebSessionStore$InMemoryWebSession@529dcf30'
2022-07-01 12:45:27.184 DEBUG 14132 --- [     parallel-2] o.s.w.s.adapter.HttpWebHandlerAdapter    : [26193fe] Completed 401 UNAUTHORIZED
2022-07-01 12:45:27.189 DEBUG 14132 --- [     parallel-2] o.s.w.r.f.client.ExchangeFunctions       : [6144e499] [609b7bfb] Response 401 UNAUTHORIZED
2022-07-01 12:45:27.207 ERROR 14132 --- [           main] o.s.t.w.reactive.server.ExchangeResult   : Request details for assertion failure:

> GET /posts
> WebTestClient-Request-Id: [1]
> Accept: [application/json]

No content

< 401 UNAUTHORIZED Unauthorized
< WWW-Authenticate: [Bearer]
< Cache-Control: [no-cache, no-store, max-age=0, must-revalidate]
< Pragma: [no-cache]
< Expires: [0]
< X-Content-Type-Options: [nosniff]
< X-Frame-Options: [DENY]
< X-XSS-Protection: [1 ; mode=block]
< Referrer-Policy: [no-referrer]

0 bytes of content (unknown content-type).


java.lang.AssertionError: Status expected:<200 OK> but was:<401 UNAUTHORIZED>
Expected :200 OK
Actual   :401 UNAUTHORIZED
<Click to see difference>

我将记录级别设置为跟踪,但是没有日志检查我们的PathMatcher规则。 似乎没有检查oferizerequest中的路径匹配者。

我已经设置了禁用 crsf ,但是CRSF过滤器仍然参与安全检查进度,匹配/注销 url也很累。

In these days, we are going to migrate our custom JWT filter to Auth0 IDP.

I was using Spring 2.7.1, WebFlux/Kotlin Coroutines in this project. I created a sample project to demo Reactive Spring Security OAuth2 with Auth0 IDP issue.

BTW, I've maintained a WebMvc version to demo Spring Security OAuth2 and OAuth0(updated to Spring 2.7.1), in which the tests are working well.

When I added org.springframework.boot:spring-boot-starter-oauth2-resource-server to our project deps to enable OAuth2 resource server support in our backend API.

But now all API endpoints are protected and returns 401 or 403.

My security config like this.

@Bean
fun springWebFilterChain(http: ServerHttpSecurity, reactiveJwtDecoder: ReactiveJwtDecoder): SecurityWebFilterChain =
http {

    csrf { disable() }
    httpBasic { disable() }
    formLogin { disable() }
    logout { disable() }

    // enable OAuth2 resource server support
    oauth2ResourceServer { jwt { jwtDecoder = reactiveJwtDecoder } }
    exceptionHandling {
        authenticationEntryPoint = problemSupport
        accessDeniedHandler = problemSupport
    }
    authorizeExchange {
        authorize(pathMatchers(GET, "/v1/me"), authenticated)
        authorize(anyExchange, permitAll)
    }
}

The testing codes is like this, check the complete codes(The tests are ported from other projects, I have not added jwt mock).

@Test
fun `get all posts`() = runTest {
    coEvery { posts.findAll() } returns flowOf(
        Post(
            id = UUID.randomUUID(),
            title = "test title",
            content = "test content"
        )
    )

    client.get()
        .uri("/posts").accept(MediaType.APPLICATION_JSON)
        .exchange()
        .expectStatus().isOk
        .expectBodyList(Post::class.java).hasSize(1)

    coVerify(exactly = 1) { posts.findAll() }
}

The get all posts endpoints is set to permitAll, when running curl http://localhost:8080/posts command in a opening Powershell, it works well and print all posts in the console.

When running test of GET /posts endpoint. I got the following info from console.

2022-07-01 12:45:27.021 DEBUG 14132 --- [           main] o.s.w.r.f.client.ExchangeFunctions       : [6144e499] HTTP GET /posts
2022-07-01 12:45:27.069 DEBUG 14132 --- [     parallel-1] o.s.w.s.adapter.HttpWebHandlerAdapter    : [26193fe] HTTP GET "/posts"
2022-07-01 12:45:27.108 DEBUG 14132 --- [     parallel-1] .s.s.w.s.u.m.AndServerWebExchangeMatcher : Trying to match using org.springframework.security.web.server.csrf.CsrfWebFilter$DefaultRequireCsrfProtectionMatcher@6fc32403
2022-07-01 12:45:27.110 DEBUG 14132 --- [     parallel-1] .s.s.w.s.u.m.AndServerWebExchangeMatcher : Did not match
2022-07-01 12:45:27.146 DEBUG 14132 --- [     parallel-2] o.s.w.s.s.DefaultWebSessionManager       : Created new WebSession.
2022-07-01 12:45:27.151 DEBUG 14132 --- [     parallel-2] o.s.s.w.s.u.m.OrServerWebExchangeMatcher : Trying to match using PathMatcherServerWebExchangeMatcher{pattern='/logout', method=POST}
2022-07-01 12:45:27.151 DEBUG 14132 --- [     parallel-2] athPatternParserServerWebExchangeMatcher : Request 'GET /posts' doesn't match 'POST /logout'
2022-07-01 12:45:27.152 DEBUG 14132 --- [     parallel-2] o.s.s.w.s.u.m.OrServerWebExchangeMatcher : No matches found
2022-07-01 12:45:27.156 DEBUG 14132 --- [     parallel-2] a.DelegatingReactiveAuthorizationManager : Checking authorization on '/posts' using org.springframework.security.authorization.AuthenticatedReactiveAuthorizationManager@66bdd968
2022-07-01 12:45:27.159 DEBUG 14132 --- [     parallel-2] ebSessionServerSecurityContextRepository : No SecurityContext found in WebSession: 'org.springframework.web.server.session.InMemoryWebSessionStore$InMemoryWebSession@529dcf30'
2022-07-01 12:45:27.160 DEBUG 14132 --- [     parallel-2] o.s.s.w.s.a.AuthorizationWebFilter       : Authorization failed: Access Denied
2022-07-01 12:45:27.174 DEBUG 14132 --- [     parallel-2] ebSessionServerSecurityContextRepository : No SecurityContext found in WebSession: 'org.springframework.web.server.session.InMemoryWebSessionStore$InMemoryWebSession@529dcf30'
2022-07-01 12:45:27.184 DEBUG 14132 --- [     parallel-2] o.s.w.s.adapter.HttpWebHandlerAdapter    : [26193fe] Completed 401 UNAUTHORIZED
2022-07-01 12:45:27.189 DEBUG 14132 --- [     parallel-2] o.s.w.r.f.client.ExchangeFunctions       : [6144e499] [609b7bfb] Response 401 UNAUTHORIZED
2022-07-01 12:45:27.207 ERROR 14132 --- [           main] o.s.t.w.reactive.server.ExchangeResult   : Request details for assertion failure:

> GET /posts
> WebTestClient-Request-Id: [1]
> Accept: [application/json]

No content

< 401 UNAUTHORIZED Unauthorized
< WWW-Authenticate: [Bearer]
< Cache-Control: [no-cache, no-store, max-age=0, must-revalidate]
< Pragma: [no-cache]
< Expires: [0]
< X-Content-Type-Options: [nosniff]
< X-Frame-Options: [DENY]
< X-XSS-Protection: [1 ; mode=block]
< Referrer-Policy: [no-referrer]

0 bytes of content (unknown content-type).


java.lang.AssertionError: Status expected:<200 OK> but was:<401 UNAUTHORIZED>
Expected :200 OK
Actual   :401 UNAUTHORIZED
<Click to see difference>

I have set logging level to TRACE, but there is no log to check our pathmatcher rules. It seems it does not check the pathmatchers in the authorizeRequest.

I have set disabled to crsf, but crsf filter still participate in the security check progress, it also tired to match the /logout url.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

巾帼英雄 2025-02-19 06:40:11

看来 webfluxtest 注释的测试未扫描我的自定义 securityconfig 它是一个简单的配置,而不是在项目中扩展xxxsecurityconfigureradapater ),但请使用Spring Boot内置默认安全配置。

目前,我必须添加我的 securityConfig 明确地启用了测试。

class TestsClass{

   @TestConfiguration
   @Import(SecuirtyConfig::class)
   class TestConfig

   //test methods
}

我不确定这是最初的设计目的或其他原因。

It seems the WebFluxTest annotated tests did not scan my custom SecurityConfig( which is a simple config NOT extends the XXXSecurityConfigurerAdapater) in the project, but use the Spring Boot built-in default security config instead.

Currently I have to add my SecurityConfig explicitly to enable it in the tests.

class TestsClass{

   @TestConfiguration
   @Import(SecuirtyConfig::class)
   class TestConfig

   //test methods
}

I am not sure it is the original design purpose or other reason.

小猫一只 2025-02-19 06:40:09

@webfluxtest / @webmvctest负载很少。我确实像您的回答一样导入我的网络安全会议。

您可能会为控制器端点测试生产安全规则。如果是这样,请导入常规安全conf(不是许可证()测试conf),并使用以下任意:

  • jwt()< / code> webtestclient mutator / webmvc postpocessor从spring-security-test
  • @ withmockjwtauth 来自春季

@WebfluxTest / @WebmvcTest load very little conf. I do import my web-security cong like you do in your answer.

You might whish to unit test the production security rules for the controller endpoint. If so, import regular security conf (not a permitAll() test conf) and configure security context with either:

  • jwt() WebTestClient mutator / WebMvc post-processor from spring-security-test
  • @WithMockJwtAuth from spring-addons
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文