3

在 Grails 2.0.3 上,我安装了 Spring Security Core 并按照教程创建了 User、UserRole 和 Role 对象:http: //blog.springsource.org/2010/08/11/simplified-spring-security-with-grails /

一切都很好,直到我决定添加第二个数据源以准备访问来自不同数据库的对象。DataSource.groovy 看起来像这样:

test {
    dataSource_product {
        dbCreate = "update"
        url = "jdbc:mysql://localhost/products"
        pooled = true
        driverClassName = "com.mysql.jdbc.Driver"
        username = "blah"
        password = "blah"
        loggingSql = true
        dialect = 'org.hibernate.dialect.MySQL5InnoDBDialect'
    }
    dataSource {
        dbCreate = "update"
        url = "jdbc:mysql://localhost/core"
        pooled = true
        driverClassName = "com.mysql.jdbc.Driver"
        username = "blah"
        password = "blah"
        loggingSql = true
        dialect = 'org.hibernate.dialect.MySQL5InnoDBDialect'
    }
}

现在我无法登录 - 即使我所做的只是添加 datasource_product。如果我将此注释掉并重新创建用户(在 Bootstrap.groovy 中),那么我可以再次登录。Bootstrap.groovy 包含:

def init =
{ servletContext ->

    // Add in roles
    Role.withTransaction { 
        def adminRole = Role.findByAuthority ( Role.ROLE_ADMIN ) ?: new Role ( authority: Role.ROLE_ADMIN ).save ( failOnError: true )

        def adminUser = User.findByUsername ( 'admin' ) ?: new User (
                username: 'blah',
                password: 'blah',
                enabled: true ).save ( failOnError: true )
        if ( !adminUser.authorities.contains ( adminRole ) ) UserRole.create ( adminUser, adminRole )
}

有任何想法吗?

4

3 回答 3

6

啊啊啊。发现这个: http: //jira.grails.org/browse/GRAILS-8237 - 显然,beforeInsert 被每个数据源的每个域调用。这意味着,在我的 User 对象中 encodePassword 被调用了两次——我对密码进行了双重编码:

def beforeInsert() {
    encodePassword()
}

def beforeUpdate() {
    if (isDirty('password'))
        encodePassword()
}

protected void encodePassword() {
    password = springSecurityService.encodePassword(password)
}

我在 JIRA 中看到了一个补丁,但在它发布之前,我使用 isPasswordEncoded 标志创建了一个解决方法,以防止用户中的多个编码:

class User {
    boolean isPasswordEncoded = false
....snip....
    def beforeInsert() {
        if ( !isPasswordEncoded )
        {
            isPasswordEncoded = true
            encodePassword ()
        }
    }

    def beforeUpdate() {
        if (isDirty('password')) {
            isPasswordEncoded = false
            encodePassword()
        }
    }
....snip....
}
于 2012-05-22T12:10:11.200 回答
3

原始答案发布的代码解决方案不适用于更新。并且也不考虑对同一对象实例的多次更新。我对插入和更新操作使用单独的标志,将它们标记为瞬态以便它们不会被持久化,并使用 afterUpdate() 事件处理程序来重置这些标志。

    static transients = ['beforeInsertRunOnce','beforeUpdateRunOnce']
    boolean beforeInsertRunOnce
    boolean beforeUpdateRunOnce

    def beforeInsert() {
        if (! beforeInsertRunOnce) {
            beforeInsertRunOnce = true
            encodePassword()
        }
    }

    def afterInsert() {
        beforeInsertRunOnce = false
    }

    def beforeUpdate() {
        if (isDirty('password') && ! beforeUpdateRunOnce ) {
            beforeUpdateRunOnce = true
            encodePassword()
        }
    }

    def afterUpdate() {
        beforeUpdateRunOnce = false
    }
于 2013-01-10T11:51:45.600 回答
0

我确实有类似的问题。是因为我忘记添加了

grails.plugin.springsecurity.userLookup.userDomainClassName ='yourpackage.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName =yourpackage.UserRole'
grails.plugin.springsecurity.authority.className ='yourpackage.Role'

之后,身份验证工作。

于 2014-07-05T11:16:12.953 回答