11. Testing Method Security(测试方法安全性)

本节演示如何使用Spring安全性的测试支持来测试基于方法的安全性。我们首先介绍一个MessageService,它要求用户通过身份验证才能访问它。

public class HelloMessageService implements MessageService {

        @PreAuthorize("authenticated")

        public String getMessage() {

                Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

                return "Hello " + authentication;

        }

}

getMessage的结果是一个字符串,对当前的Spring安全认证说“你好”。输出示例如下所示。

Hello

org.springframework.security.authentication.UsernamePasswordAuthenticationToken@ca25360: 

Principal: org.springframework.security.core.userdetails.User@36ebcb:

 Username: user;

 Password: [PROTECTED]; 

Enabled: true; AccountNonExpired: true; 

credentialsNonExpired: true; 

AccountNonLocked: true; 

Granted Authorities: ROLE_USER; 

Credentials: [PROTECTED]; 

Authenticated: true;

 Details: null;

 Granted Authorities: ROLE_USER

11.1 Security Test Setup(安全测试设置)

在使用Spring安全测试支持之前,我们必须执行一些设置。下面是一个例子:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class WithMockUserTests {

这是如何设置spring安全测试的一个基本示例。亮点是:

@RunWith指示spring-test模块应该创建一个应用上下文。这与使用现有的spring-test支持没有什么不同。有关更多信息,请参考 [Spring Reference](https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/htmlsingle/#integration-testing-annotations-standard)

@ContextConfiguration指示spring-test用于创建应用程序上下文的配置。由于未指定配置,将尝试默认配置位置。这与使用现有的spring-test支持没有什么不同。有关更多信息,请参考 [Spring Reference](https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/htmlsingle/#integration-testing-annotations-standard)

Spring安全性使用WithSecurityContextTestExecutionListener连接到Spring Test支持,这将确保我们的Spring Test由正确的用户运行。它通过在运行测试之前填充SecurityContextHolder来实现这一点。测试完成后,它将清除SecurityContextHolder.如果您只需要Spring安全相关的支持,您可以用@ SecurityTestExecutionListeners替换@ContextConfiguration。

请记住,我们在我们的HelloMessageService中添加了@PreAuthorize注释,因此它需要一个经过身份验证的用户来调用它。
如果我们运行下面的测试,我们希望下面的测试能够通过:
@Test(expected = AuthenticationCredentialsNotFoundException.class)
public void getMessageUnauthenticated() {
messageService.getMessage();
}

11.2 @WithMockUser(使用模拟用户)

 

11.3 @WithAnonymousUser(使用匿名用户)

使用@ WithAnonymousUser允许以匿名用户身份运行。当您希望用特定用户运行大多数测试,但希望以匿名用户身份运行一小部分测试时,这一点尤其方便。

例如,以下将使用@WithMockUser和匿名用户作为匿名用户与MockUser1和MockUser2一起运行。

 


 

11.4 @WithUserDetails(用户详细信息)

虽然@WithMockUser是一种非常方便的入门方式,但它可能并不适用所有情况。例如,应用程序通常希望身份验证主体是特定类型的。这样做是为了使应用程序可以将主体作为自定义类型引用,并减少Spring Security上的耦合。

自定义主体通常由自定义用户详细信息服务返回,该服务返回实现用户详细信息和自定义类型的对象。对于这种情况,使用自定义的用户详细信息服务创建测试用户是很有用的。这正是@WithUserDetails所做的。

假设我们有一个作为bean公开的UserDetailservice,下面的测试将使用类型为UserNamePasswordAuthenticationToken的身份验证和从UserDetailservice返回的用户名为“user”的主体来调用。


 

我们还可以定制用于从我们的UserDetailsService中查找用户的用户名。例如,该测试将使用用户名为“自定义用户名”的UserDetailsService 返回的主体来执行。

 


 

我们还可以提供一个显式的bean名称来查找UserDetailsService。例如,该测试将使用用户名为“myUserDetailsService”的bean来查找用户名“customUsername”。

 


 

像@WithMockUser一样,我们也可以在类级别放置我们的注释,以便每个测试使用相同的用户。但是与@WithMockUser不同的是,@WithUserDetails要求用户存在。

11.5 @WithSecurityContext(使用安全上下文)

我们已经看到,如果我们不使用自定义身份验证主体,那么@WithMockUser是一个很好的选择。接下来,我们发现@WithUserDetails将允许我们使用自定义的UserDetailsService来创建我们的身份验证主体,但要求用户存在。我们现在将看到一个允许最大灵活性的选项。

我们可以创建自己的注释,使用@WithSecurityContext来创建我们想要的任何SecurityContext(安全上下文)。例如,我们可以创建一个名为@WithMockCustomUser的注释,如下所示:

 


 

您可以看到@WithMockCustomUser用@WithSecurityContext注释进行了注释。这是向Spring安全测试支持发出的信号,表明我们打算为测试创建一个安全上下文。@WithSecurityContext注释要求我们指定一个安全上下文工厂,该工厂将根据我们的@ WithMockCustomUser注释创建一个新的安全上下文。您可以在下面找到我们的WithMockCustomUserSecurityContextFactory实现:

 


 

我们现在可以用新的注释来注释测试类或测试方法,而Spring Security的WithSecurityContextTestExecutionListener将确保我们的SecurityContext被适当地填充。

当使用安全上下文工厂实现创建您自己的实现时,很高兴知道它们可以用标准的Spring注释进行注释。例如,WithUserDetailsSecurityContextFactory使用@Autowired注释来获取用户详细信息服务:


 

11.6 Test Meta Annotations(测试元注释)

如果您经常在测试中重用同一个用户,那么重复指定属性是不理想的。例如,如果有许多与用户名为“admin”且角色为ROLE_USER和ROLE_ADMIN的管理用户相关的测试,您必须编写:

@WithMockUser(username="admin",roles={"USER","ADMIN"})

我们可以使用元注释,而不是到处重复。例如,我们可以创建一个名为WithMockAdmin的元注释:

@Retention(RetentionPolicy.RUNTIME)

@WithMockUser(value="rob",roles="ADMIN")

public@interfaceWithMockAdmin { }

现在我们可以像使用更详细的@WithMockUser一样使用@WithMockAdmin。

元注释与上面描述的任何测试注释一起工作。例如,这意味着我们也可以为@ WithUserDetails(“admin”)创建一个元注释。

 

posted @ 2020-08-16 17:08  节日快乐  阅读(271)  评论(0编辑  收藏  举报