@WithMockUser与自定义用户实现

Ste*_*kov 5 java spring unit-testing spring-security spring-security-oauth2

我正在使用Spring OAuth2和JWT令牌来保护应用程序。我正在扩展org.springframework.security.core.userdetails,以便向令牌添加一些其他属性,然后可以将这些属性用于执行称为端点的授权。

public class CustomUser extends User {
     private Set<String> bookIds;

     public CustomUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {
         super(username, password, authorities);
     }

     public CustomUser(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
         super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
     }
}
Run Code Online (Sandbox Code Playgroud)

我也有一个org.springframework.security.access.PermissionEvaluator的自定义实现,它可以反序列化令牌并检查自定义属性是否是其中的一部分,可以将其本身添加到控制器端点。

@PreAuthorize("hasPermission(authentication, #bookId,'read')")
Run Code Online (Sandbox Code Playgroud)

现在一切正常,我可以通过邮递员测试我的应用程序,只有拥有有效JWT令牌且在bookIds设置的URL部分中具有bookID的用户才能访问资源

@PreAuthorize("hasPermission(authentication, #bookId,'read')")
@GetMapping(value = "api/books/{bookId}")
public Book getBook(@PathVariable String bookId) {}
Run Code Online (Sandbox Code Playgroud)

但是,我正在为此进行测试,因为这是微服务应用程序的一部分,其中身份验证和服务不是同一项目的一部分,而是可以在单独的VM上运行。理想情况下,我希望能够在每个服务中模拟令牌并在bookId集中添加所需的任何值。我知道在Spring 4之后,我们可以使用@WithMockUser,但是据我所知这仅限于用户名/密码/角色/授权,例如:

@WithMockUser(username = "ram", roles={"ADMIN"})
Run Code Online (Sandbox Code Playgroud)

我真正想做的是扩展此批注以支持我的自定义属性“ bookId”,或向其中注入模拟集的方法。这有可能吗?如果没有,那我有什么选择,因为我无法在单元测试中调用身份验证提供程序,因为该实现将存在于单独应用程序中托管的另一个spring上下文中。

提前谢谢了 !

Ele*_*ana 12

您可以使用@WithUserDetails注释。
如果您有一个用户名为“user1”的用户,那么您可以使用@WithUserDetails("user1")它来注释您的测试,并且它将使用一个CustomUser主体执行,包括与“user1”关联的自定义属性“bookId”。
您可以在spring-security 文档中找到有关注释的更多信息。

如果你想要更大的灵活性,你也可以使用@WithSecurityContext注解。
这允许您创建自己的注释,例如@WithMockCustomUser,您可以自己设置安全上下文。
您可以在spring-security 文档中找到更多详细信息。

还有一种选择,如果您要MockMvc用于运行测试,则使用请求后处理器
你的测试看起来像这样

mvc
    .perform(get("/api/books/1")
    .with(user(customUser)));
Run Code Online (Sandbox Code Playgroud)

您在测试中创建customUser的实例在哪里CustomUser