问题描述
我想为使用JWT令牌验证的Rest API创建JUnit 5测试:
I want to create JUnit 5 test for Rest API which uses JWT token validation:
@Test
public void resetTokenTest_OK() throws Exception {
when(userService.findByResetPasswordToken(anyString())).thenReturn(trueOptional);
mockMvc.perform(post("/users/reset_token")
.contentType(MediaType.APPLICATION_JSON)
.content(ResetPasswordTokenDTO))
.andExpect(status().isOk())
.andExpect(jsonPath("$.resetPasswordToken").value(randomString_254))
.andExpect(jsonPath("$.login").value("login"))
.andExpect(jsonPath("$.status").value("200"))
.andExpect(jsonPath("$.error").value(""))
.andExpect(jsonPath("$.errorDescription").value(""));
}
我使用此有效负载发出一个样机请求:
I make a Mockup request using this payload:
{
"resetPasswordToken": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.VFb0qJ1LRg_4ujbZoRMXnVkUgiuKq5KxWqNdbKq_G9Vvz-S1zZa9LPxtHWKa64zDl2ofkT8F6jBt_K4riU-fPg",
"login": "login",
"status": "1",
"error": "",
"errorDescription": ""
}
我为此行:
Caused by: java.lang.NullPointerException
at org.engine.utils.GenericUtils.getLoggedInUser(GenericUtils.java:15)
at org.engine.rest.UsersController.lambda$resetToken$0(UsersController.java:159)
at java.base/java.util.Optional.map(Optional.java:258)
at org.engine.rest.UsersController.resetToken(UsersController.java:153)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
完整日志:
我获得此代码的NPE:
I get NPE for this code:
return (Users) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
如何模拟SecurityContextHolder.getContext().getAuthentication().getPrincipal()
的结果以免获得NPE?
How I can mock the result from SecurityContextHolder.getContext().getAuthentication().getPrincipal()
in order not to get NPE?
推荐答案
有多种方法可以使用@WithMockUser
,@WithAnonymousUser
,@WithUserDetails
,@WithSecurityContext
来模拟安全性.您可以将这些注释与@Test
方法一起使用
There are multiple ways to mock the security using @WithMockUser
, @WithAnonymousUser
, @WithUserDetails
, @WithSecurityContext
. You can use these annotations with @Test
method
- 由于我们正在嘲笑用户,因此用户名"user"的用户不必存在
-
SecurityContext
中填充的身份验证的类型为UsernamePasswordAuthenticationToken
- 身份验证的主体是Spring Security的User对象
- 该用户的用户名为"user" ,密码为"password" ,并且一个名为"ROLE_USER" 的GrantedAuthority为使用.
- 您可以自定义参数,例如用户名,角色,值
- The user with the username "user" does not have to exist since we are mocking the user
- The Authentication that is populated in the
SecurityContext
is of typeUsernamePasswordAuthenticationToken
- The principal on the Authentication is Spring Security’s User object
- The User will have the username of "user", the password "password", and a single GrantedAuthority named "ROLE_USER" is used.
- You may customize the parameters such as username, roles, value
使用@WithAnonymousUser
允许以匿名用户身份运行.当您希望与特定用户一起运行大多数测试,但又想以匿名用户身份运行一些测试时,这特别方便.例如,下面的代码将使用@WithMockUser
和 anonymous作为匿名用户,在withMockUser1和withMockUser2上运行.
Using @WithAnonymousUser
allows running as an anonymous user. This is especially convenient when you wish to run most of your tests with a specific user, but want to run a few tests as an anonymous user. For example, the following will run withMockUser1 and withMockUser2 using @WithMockUser
and anonymous as an anonymous user.
虽然@WithMockUser
是一种非常方便的入门方法,但在所有情况下 都可能不起作用.例如,对于应用程序来说,通常期望Authentication
主体是特定类型.这样做是为了使应用程序可以将委托人称为自定义类型,并减少Spring Security上的耦合.
While @WithMockUser
is a very convenient way to get started, it may not work in all instances. For example, it is common for applications to expect that the Authentication
principal be of a specific type. This is done so that the application can refer to the principal as the custom type and reduce coupling on Spring Security.
自定义主体通常由自定义UserDetailsService
返回,该自定义UserDetailsService
返回同时实现UserDetails
和自定义类型的对象.在这种情况下,使用自定义UserDetailsService创建测试用户非常有用.这正是@WithUserDetails
的作用.
The custom principal is often times returned by a custom UserDetailsService
that returns an object that implements both UserDetails
and the custom type. For situations like this, it is useful to create the test user using the custom UserDetailsService. That is exactly what @WithUserDetails
does.
我们可以创建自己的注释,该注释使用@WithSecurityContext创建所需的任何SecurityContext.例如,我们可以创建一个名为@WithMockCustomUser的注释为@WithSecurityContext(factory = WithMockCustomUserSecurityContextFactory.class)
We can create our own annotation that uses the @WithSecurityContext to create any SecurityContext we want. For example, we might create an annotation named @WithMockCustomUser as @WithSecurityContext(factory = WithMockCustomUserSecurityContextFactory.class)
这篇关于Spring Boot:使用Junit模拟具有安全上下文的用户身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!