【问题标题】:Secured users created in grails integration test are unauthorized but bootstrapped ones are在 grails 集成测试中创建的安全用户是未经授权的,但引导的用户是未经授权的
【发布时间】:2018-01-05 01:37:50
【问题描述】:

我正在使用Grails Spring Security CoreGrails Spring Security REST plugin,我刚刚开始设置。我用User 类和Authority 类(默认值)初始化插件,然后在guide I found on the Grails website 之后编写集成测试。

据说将以下内容放入集成测试中:

def "test a user with the role ROLE_BOSS is able to access /api/announcements url"() {
    when: 'login with the sherlock'
    RestBuilder rest = new RestBuilder()
    def resp = rest.post("http://localhost:${serverPort}/api/login") { 
        accept('application/json')
        contentType('application/json')
        json {
            username = 'sherlock'
            password = 'elementary'
        }
    }

    then:
    resp.status == 200
    resp.json.roles.find { it == 'ROLE_BOSS' }
}

我继续做了类似的事情,它与自举的User 一起工作,但是当我尝试使用在测试方法本身中创建的User 进行完全相同的测试时,它会因401 而失败HTTP 响应代码。

我正在尝试运行的代码:

void "check get access token"() {
    given:
    RestBuilder rest = new RestBuilder()
    new User(username: "securitySpecTestUserName", password: "securitySpecTestPassword").save(flush: true)
    assert User.count == 2

    when:
    def resp = rest.post("http://localhost:${serverPort}/api/login") {
        accept('application/json')
        contentType('application/json')
        json {
            username = "securitySpecTestUserName"
            password = "securitySpecTestPassword"
        }
    }

    then:
    resp.status == 200
}

请注意,User.count == 2 断言通过了,因为Bootstrap.groovy 中有一个User,而测试方法中有一个 create。

为什么这可以正常工作并与引导的User 一起通过而没有任何问题,但不是在方法中创建的问题?有没有办法可以编写这个集成测试,以便我可以通过这种方式测试 grails-spring-security-rest 插件中包含的 /api/login 端点?

【问题讨论】:

  • 能否检查一下用户是否已启用、accountLocked、accountExpired 是否设置为 true?
  • @dynamo 不幸的是 enabled = trueaccountExpired = falseaccountLocked = falsepasswordExpired = false,就像引导用户一样。

标签: spring grails spring-security grails-rest-api


【解决方案1】:

您在给定部分中创建的用户处于尚未提交的事务中。当您进行 REST 调用时,api/login 控制器将在一个看不到您未提交的用户的新事务中运行。

一些选项(还有其他选项)...

  1. 在 BootStrap.groovy 中创建用户

    def init = { servletContext ->
      environments {
        test {
          new User(username: "securitySpecTestUserName", password: "securitySpecTestPassword").save(flush: true)
        }
      }
    }
    
  2. 进行 REST 调用以创建用户 - 假设您具有此类功能

  3. 在设置中创建用户

    @Integration
    @Rollback
    class UserIntSpec extends Specification {
    
      def setup() {
        new User(username: "securitySpecTestUserName", password: "securitySpecTestPassword").save(flush: true)
      }
    
      void "check get access token"() {
        given:
        RestBuilder rest = new RestBuilder()
    
        when:
        def response = rest.post("http://localhost:${serverPort}/api/login") {
          accept('application/json')
          contentType('application/json')
          json {
            username = "securitySpecTestUserName"
            password = "securitySpecTestPassword"
          }
        }
    
       then:
       response.status == HttpServletResponse.SC_OK
    
       when:
       def token = response.json.access_token
    
       then:
       token
      }
    }
    

注意:在 Grails >= 3.0 中,setup() 在单独的事务中运行并持久化(为什么它可以解决您的问题),不会回滚。任何数据都需要手动清理。

我建议您阅读有关测试的 grails 文档:Integration Testing

【讨论】:

  • 谢谢!我已经彻底阅读了文档,但我没有意识到事务未提交意味着用户将无法通过 Spring Security 进行身份验证。我认为它会在.save() 上为用户设置,即使它没有保存到数据库中。我现在已将代码移至 setup() 方法,现在可以执行测试了。
猜你喜欢
  • 2016-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-15
  • 1970-01-01
  • 2019-09-29
  • 1970-01-01
  • 2023-03-17
相关资源
最近更新 更多