本文介绍了Spring Boot:使用Junit模拟具有安全上下文的用户身份验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想为使用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(""));
    }

GitHub

我使用此有效负载发出一个样机请求:

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();

GitHub

如何模拟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

@WithMockUser

  • 由于我们正在嘲笑用户,因此用户名"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 type UsernamePasswordAuthenticationToken
  • 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

使用@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.

@WithUserDetails

虽然@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和自定义类型的对象.在这种情况下,使用自定义UserDetailsS​​ervice创建测试用户非常有用.这正是@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

我们可以创建自己的注释,该注释使用@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模拟具有安全上下文的用户身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-28 04:58
查看更多