【问题标题】:mocking authentication spring security模拟身份验证弹簧安全性
【发布时间】:2012-02-15 07:39:03
【问题描述】:

我有一个使用@Secured 注释的存储库方法。我正在尝试为此方法编写单元测试,但我的测试失败,因为我需要身份验证才能调用该方法。该方法本身恰好是 save() 方法。我调用该方法时得到的错误是:

 org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext

我无法测试此方法,因为它需要身份验证,并且我无法保存用户进行身份验证(我正在使用 hsqldb),因为我需要调用此方法来保存。关于如何对使用 @secured 注释的方法进行单元测试或如何模拟身份验证的任何建议。

【问题讨论】:

    标签: spring spring-security


    【解决方案1】:

    这取决于您要测试的内容。

    • 如果您想在没有任何安全性的情况下测试应用程序的业务逻辑,您可以完全禁用安全性。假设您使用SpringJunit4Runner,您可以将安全配置放在单独的文件中,不要将其包含在@ContextConfiguration中。

    • 如果你想测试授权(例如@Secured 注释的正确工作),你可以直接访问SecurityContext,绕过所有与身份验证相关的东西(在这种情况下,你可以将身份验证配置放在单独的文件中,不要也加载它):

      您只需将适当的Authentication 对象放入SecurityContextHolder

      @Test
      public void myTest() {
          login(...);
          ...
          logout();
      }
      
      private void login(...) {
          SecurityContextHolder.getContext().setAuthentication(
              new UsernamePasswordAuthenticationToken(...)
          )
      }
      
      private void logout() {
          SecurityContextHolder.clearContext();
      }
      
    • 最后,如果要测试身份验证,可以使用包含测试数据的数据库运行测试。

    【讨论】:

    • 不幸的是我不能这样做。我的身份验证管理器是一个自定义 userDetailService,它使用我的存储库从数据库中获取用户。因此,如果我无法将用户保存到持久性中,那么 userDetailsS​​ervice 将找不到该用户,从而导致 BadCredentials 异常。
    【解决方案2】:

    a) 这不是单元测试,而是集成测试。单元测试没有问题。

    b) 我会尽量让您的测试设置分开。为什么不在不测试安全相关功能的测试中停用 spring 安全性?

    c) 如果一切都失败了:注入一个JdbcTemplate 对象并在测试设置期间在 SQL 中手动创建用户数据。见Support classes for integration testing

    【讨论】:

    • 我不知道可以在运行时停用安全性。您是否有资源也可以链接我以查看如何停用安全性?
    • @vikashdat 换一种方式:不要激活它。当然,这取决于这是什么类型的测试。如果您正在针对已部署的服务器进行测试,这可能不是一个选项。
    • 我不确定我是否理解..我怎么不能激活它?您的意思是不使用 SpringJunit4Runner 运行测试吗?如果这样做,我将失去自动装配组件的能力。
    • @vikashdat 使用 SpringJunit4Runner,但使用了不了解 spring 安全性的 spring 上下文
    • 它不应该有任何安全元素,具体来说,<global-method-security>
    【解决方案3】:

    我会考虑使用诸如@WithMockUser 之类的注释来使用“角色”(具有特定权限的测试用户,例如“管理员”、“销售员”等)填充测试安全上下文。

    如果@Secured 在 repo 上,那一定是因为规范声明了“用户必须拥有此授权才能查询”之类的内容,因此也应该对安全性进行单元测试。

    如果UsernameAuthenticationToken@WithMockUser 创建的)不能满足您的需求,那么您可以选择其他注释,例如我写的 this one,或者甚至编写自己的注释来创建确切的 Authentication 实现你想要的。

    Libs here,从there提取的样本结果

    @RunWith(SpringRunner.class)
    @Import(JwtAuthenticationTokenMessageServiceTests.TestConfig.class)
    public class JwtAuthenticationTokenMessageServiceTests {
    
        @Autowired
        private MessageService<JwtAuthenticationToken> messageService;
    
        @Test
        @WithMockAuthentication(authType = JwtAuthenticationToken.class, authorities = "ROLE_AUTHORIZED_PERSONNEL")
        public void secretWithScopeAuthorizedPersonnelAuthority() {
            assertThat(messageService.getSecret()).isEqualTo("Secret message");
        }
    
        @TestConfiguration
        @EnableGlobalMethodSecurity(prePostEnabled = true)
        @Import({ JwtTestConf.class, JwtAuthenticationTokenServletApp.JwtAuthenticationTokenMessageService.class })
        public static class TestConfig {
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-04
      • 2021-06-05
      • 2017-09-22
      • 2020-06-21
      • 2014-05-20
      • 1970-01-01
      • 2017-04-13
      • 2014-03-06
      相关资源
      最近更新 更多