如何在Spring Boot中模拟JwtDecoder以进行已验证控制器的集成测试?

huangapple go评论52阅读模式
英文:

How to mock JwtDecoder in Spring Boot for integration testing of authenticated controllers?

问题

在我的Spring Boot应用程序中,有一些经过身份验证的控制器。
操作模式是"OAuth2资源服务器",因此我的应用程序依赖于某个任意的OAuth2授权服务器(假设是Keycloak,尽管这不应影响模拟的方式)。

所以问题是:

如何正确地模拟JwtDecoder,以便能够传递一些静态字符串作为Bearer令牌?

(请记住,这是一个负责令牌发放的第三方服务器;因此,我不能在测试中依赖它。我想要模拟它以便能够离线运行测试,例如)

我期望发生的事情的一个示例:

  1. 我模拟JwtDecoder(假装我创建了一些<token字符串,UserData>的映射)。
  2. 我使用基于MockMvc的HTTP调用访问带有这个静态字符串的授权控制器(Authorization标头:Bearer STATIC_STRING)。控制器测试被标记为@SpringBootTest@AutoConfigureMockMvc
  3. 我期望JwtAuthenticationToken填充了来自模拟的JwtDecoder映射中UserData的数据。

我已经尝试只是创建一个具有所有描述特性的JwtDecoder实现的bean。我看到这个bean被添加到配置中,但整个测试最终会出现AuthenticationCredentialsNotFoundException:在SecurityContext中未找到Authentication对象。因此,我认为JwtDecoder从未被调用(用调试器检查过),整个测试设置错误配置,但我不确定应该更改什么。

我错过了什么?

英文:

In my Spring Boot application, there are some authenticated controllers.
The operation mode is "OAuth2 resource server", so my application relies on some arbitrary OAuth2 authorization server. (Let's say it's Keycloak, though it should not affect the way of mocking)

So, the question is:

What is the right way to mock JwtDecoder, in order to be able to pass some static strings as the bearer tokens?

(Please remember, it's a third party server responsible for the token issuing; So I cannot rely on it in tests. I want to mock it away to be able to run tests offline for example)

An example of what I expect to happen:

  1. I mock JwtDecoder (let's pretend I've created some map of &lt;token string, UserData&gt;)
  2. I make a MockMvc-based http call to the authenticated controller with this static string in the Authorization header (Authorization: Bearer STATIC_STRING). The controller test is decorated with @SpringBootTest and @AutoConfigureMockMvc.
  3. I expect to have JwtAuthenticationToken filled with data from UserData from the map of the mocked JwtDecoder.

I've already tried to just create a bean of JwtDecoder implementation with all the described features. I see this bean is added to the configuration, but still whole test ends up in AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext. So I presume that JwtDecoder is never called (checked that with the debugger), and the whole testing setup is misconfigured, but I don't know for sure what to change.

What do I miss?

答案1

得分: 1

使用MockMvc(以及反应式应用中的WebTestClient)时,Authorization头部只是被忽略(不解码、验证、审查或其他操作)。

测试安全上下文可以直接设置(SecurityContextHolder.createEmptyContext().setAuthentication(auth);),或者可以使用以下方式之一进行设置:

  • 测试注解(比如@WithMockUser,但这个不太适用于模拟OAuth2身份)。请参考我在OAuth2的这个库中创建的注解
  • 用于MockMvc的请求后处理器
  • 用于WebTestClient的修改器

更多详细信息请参考以下其他答案:

英文:

With MockMvc (as well as WebTestClient in reactive apps) the Authorization header is just ignored (not decoded, validated, introspected or whatever).

The test security context is to be set directly (SecurityContextHolder.createEmptyContext().setAuthentication(auth);) or with the help of either:

  • test annotations (like @WithMockUser, but this one is not quite adapted to mocking OAuth2 identities). Refer to those that I created in this lib for OAuth2
  • Request post-processors for MockMvc
  • mutators for WebTestClients

More details in this other answers:

huangapple
  • 本文由 发表于 2023年2月16日 03:56:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/75464857.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定