问题
On Grails 2.0.3, I installed Spring Security Core and created the User, UserRole and Role objects as per the tutorial: http://blog.springsource.org/2010/08/11/simplified-spring-security-with-grails/
All went fine until I decided to add a second datasource in preparation for accessing objects from a different database. DataSource.groovy looks like this:
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'
}
}
Now I can't log in - even though all I have done is add datasource_product. If I comment this out and recreating the users (in Bootstrap.groovy) then I can log in again. Bootstrap.groovy contains:
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 )
}
Any ideas?
回答1:
Gaaaahh. Found this: http://jira.grails.org/browse/GRAILS-8237 - apparently, beforeInsert gets called on each domain for every datasource. This means that, in my User object encodePassword is getting called twice - I'm double-encoding the password:
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password'))
encodePassword()
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}
I saw a patch in the JIRA, but until it gets into the release, I created a workaround using an isPasswordEncoded flag to prevent multiple encodes in User:
class User {
boolean isPasswordEncoded = false
....snip....
def beforeInsert() {
if ( !isPasswordEncoded )
{
isPasswordEncoded = true
encodePassword ()
}
}
def beforeUpdate() {
if (isDirty('password')) {
isPasswordEncoded = false
encodePassword()
}
}
....snip....
}
回答2:
Code solution posted by original answer doesn't work for update. And also doesn't consider multiple updates to same object instance. I use separate flags for insert and update operations, mark them as transient so they're not persisted, and use the afterUpdate() event handler to reset these flags.
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
}
回答3:
I did have similar issue. Was because I've forgotten to add
grails.plugin.springsecurity.userLookup.userDomainClassName ='yourpackage.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName =yourpackage.UserRole'
grails.plugin.springsecurity.authority.className ='yourpackage.Role'
After that authentication was working.
来源:https://stackoverflow.com/questions/10695592/grails-2-cant-login-with-spring-security-when-using-multiple-databases