我正在使用带有grails 2.3.4
和":spring-security-ui:1.0-RC1"
插件的':spring-security-core:2.0-RC2'
。我在Config.groovy
中配置了两个插件:
grails.plugin.springsecurity.userLookup.userDomainClassName = 'com.SaaSTemplate.auth.Person'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'com.SaaSTemplate.auth.PersonRole'
grails.plugin.springsecurity.authority.className = 'com.SaaSTemplate.auth.Role'
//**********************************
// Spring Security UI Settings
//**********************************
//password validation of RegisterController.groovy
grails.plugin.springsecurity.ui.password.validationRegex='^.*(?=.*\\d)(?=.*[a-zA-Z])(?=.*[!@#$%^&]).*$' //example: 1Test@!!
grails.plugin.springsecurity.ui.password.minLength=8
grails.plugin.springsecurity.ui.password.maxLength=64
我的RegisterController.groovy
看起来像这样:
@Secured(['permitAll'])
class RegisterController extends grails.plugin.springsecurity.ui.RegisterController {
// override default value from base class
static defaultAction = 'index'
// override default value from base class
static allowedMethods = [register: 'POST']
def mailService
def messageSource
def saltSource
def index() {
def copy = [:] + (flash.chainedParams ?: [:])
copy.remove 'controller'
copy.remove 'action'
[command: new RegisterCommand(copy)] // here is where I get the exception!!!!
}
def register(RegisterCommand command) {
if (command.hasErrors()) {
render view: 'index', model: [command: command]
return
}
String salt = saltSource instanceof NullSaltSource ? null : command.username
def user = lookupUserClass().newInstance(email: command.email, username: command.username,
accountLocked: true, enabled: true)
RegistrationCode registrationCode = springSecurityUiService.register(user, command.password, salt)
if (registrationCode == null || registrationCode.hasErrors()) {
// null means problem creating the user
flash.error = message(code: 'spring.security.ui.register.miscError')
flash.chainedParams = params
redirect action: 'index'
return
}
String url = generateLink('verifyRegistration', [t: registrationCode.token])
def conf = SpringSecurityUtils.securityConfig
def body = conf.ui.register.emailBody
if (body.contains('$')) {
body = evaluate(body, [user: user, url: url])
}
mailService.sendMail {
to command.email
from conf.ui.register.emailFrom
subject conf.ui.register.emailSubject
html body.toString()
}
render view: 'index', model: [emailSent: true]
}
def verifyRegistration() {
def conf = SpringSecurityUtils.securityConfig
String defaultTargetUrl = conf.successHandler.defaultTargetUrl
String token = params.t
def registrationCode = token ? RegistrationCode.findByToken(token) : null
if (!registrationCode) {
flash.error = message(code: 'spring.security.ui.register.badCode')
redirect uri: defaultTargetUrl
return
}
def user
// TODO to ui service
RegistrationCode.withTransaction { status ->
String usernameFieldName = SpringSecurityUtils.securityConfig.userLookup.usernamePropertyName
user = lookupUserClass().findWhere((usernameFieldName): registrationCode.username)
if (!user) {
return
}
user.accountLocked = false
user.save(flush:true)
def UserRole = lookupUserRoleClass()
def Role = lookupRoleClass()
for (roleName in conf.ui.register.defaultRoleNames) {
UserRole.create user, Role.findByAuthority(roleName)
}
registrationCode.delete()
}
if (!user) {
flash.error = message(code: 'spring.security.ui.register.badCode')
redirect uri: defaultTargetUrl
return
}
springSecurityService.reauthenticate user.username
flash.message = message(code: 'spring.security.ui.register.complete')
redirect uri: conf.ui.register.postRegisterUrl ?: defaultTargetUrl
}
def forgotPassword() {
if (!request.post) {
// show the form
return
}
String username = params.username
if (!username) {
flash.error = message(code: 'spring.security.ui.forgotPassword.username.missing')
redirect action: 'forgotPassword'
return
}
String usernameFieldName = SpringSecurityUtils.securityConfig.userLookup.usernamePropertyName
def user = lookupUserClass().findWhere((usernameFieldName): username)
if (!user) {
flash.error = message(code: 'spring.security.ui.forgotPassword.user.notFound')
redirect action: 'forgotPassword'
return
}
def registrationCode = new RegistrationCode(username: user."$usernameFieldName")
registrationCode.save(flush: true)
String url = generateLink('resetPassword', [t: registrationCode.token])
def conf = SpringSecurityUtils.securityConfig
def body = conf.ui.forgotPassword.emailBody
if (body.contains('$')) {
body = evaluate(body, [user: user, url: url])
}
mailService.sendMail {
to user.email
from conf.ui.forgotPassword.emailFrom
subject conf.ui.forgotPassword.emailSubject
html body.toString()
}
[emailSent: true]
}
def resetPassword(ResetPasswordCommand command) {
String token = params.t
def registrationCode = token ? RegistrationCode.findByToken(token) : null
if (!registrationCode) {
flash.error = message(code: 'spring.security.ui.resetPassword.badCode')
redirect uri: SpringSecurityUtils.securityConfig.successHandler.defaultTargetUrl
return
}
if (!request.post) {
return [token: token, command: new ResetPasswordCommand()]
}
command.username = registrationCode.username
command.validate()
if (command.hasErrors()) {
return [token: token, command: command]
}
String salt = saltSource instanceof NullSaltSource ? null : registrationCode.username
RegistrationCode.withTransaction { status ->
String usernameFieldName = SpringSecurityUtils.securityConfig.userLookup.usernamePropertyName
def user = lookupUserClass().findWhere((usernameFieldName): registrationCode.username)
user.password = springSecurityUiService.encodePassword(command.password, salt)
user.save()
registrationCode.delete()
}
springSecurityService.reauthenticate registrationCode.username
flash.message = message(code: 'spring.security.ui.resetPassword.success')
def conf = SpringSecurityUtils.securityConfig
String postResetUrl = conf.ui.register.postResetUrl ?: conf.successHandler.defaultTargetUrl
redirect uri: postResetUrl
}
protected String generateLink(String action, linkParams) {
createLink(base: "$request.scheme://$request.serverName:$request.serverPort$request.contextPath",
controller: 'register', action: action,
params: linkParams)
}
protected String evaluate(s, binding) {
new SimpleTemplateEngine().createTemplate(s).make(binding)
}
// static final passwordValidator = { String password, command ->
// if (command.username && command.username.equals(password)) {
// return 'command.password.error.username'
// }
//
// if (!checkPasswordMinLength(password, command) ||
// !checkPasswordMaxLength(password, command) ||
// !checkPasswordRegex(password, command)) {
// return 'command.password.error.strength'
// }
// }
static boolean checkPasswordMinLength(String password, command) {
def conf = SpringSecurityUtils.securityConfig
int minLength = conf.ui.password.minLength instanceof Number ? conf.ui.password.minLength : 8
password && password.length() >= minLength
}
static boolean checkPasswordMaxLength(String password, command) {
def conf = SpringSecurityUtils.securityConfig
int maxLength = conf.ui.password.maxLength instanceof Number ? conf.ui.password.maxLength : 64
password && password.length() <= maxLength
}
static boolean checkPasswordRegex(String password, command) {
def conf = SpringSecurityUtils.securityConfig
String passValidationRegex = conf.ui.password.validationRegex ?:
'^.*(?=.*\\d)(?=.*[a-zA-Z])(?=.*[!@#$%^&]).*$'
password && password.matches(passValidationRegex)
}
// static final password2Validator = { value, command ->
// if (command.password != command.password2) {
// return 'command.password2.error.mismatch'
// }
// }
}
class RegisterCommand {
String username
String email
String password
String password2
def grailsApplication
static constraints = {
username blank: false, validator: { value, command ->
if (value) {
def User = command.grailsApplication.getDomainClass(
SpringSecurityUtils.securityConfig.userLookup.userDomainClassName).clazz
if (User.findByUsername(value)) {
return 'registerCommand.username.unique'
}
}
}
email blank: false, email: true
password blank: false, validator: RegisterController.passwordValidator
password2 validator: RegisterController.password2Validator
}
}
class ResetPasswordCommand {
String username
String password
String password2
static constraints = {
password blank: false, validator: RegisterController.passwordValidator
password2 validator: RegisterController.password2Validator
}
}
如您所见,我刚从源代码中复制了原始控制器。因此,还包括其他类ResetPasswordCommand
和RegisterCommand
。但是,我仍然得到例外:
ui.SpringSecurityUiService problem creating Person: com.TestApp.auth.Person : (unsaved)
Die Eigenschaft [firstName] des Typs [class com.TestApp.auth.Person] darf nicht null sein
Die Eigenschaft [lastName] des Typs [class com.TestApp.auth.Person] darf nicht null sein
errors.GrailsExceptionResolver MissingPropertyException occurred when processing request: [GET] /TestApp/register/index
No such property: format for class: TestApp.Register.RegisterCommand. Stacktrace follows:
groovy.lang.MissingPropertyException: No such property: format for class: TestApp.Register.RegisterCommand
at TestApp.Register.RegisterController.index(RegisterController.groovy:26)
at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:200)
at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
at grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter.doFilter(GrailsAnonymousAuthenticationFilter.java:53)
at grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter.doFilter(RequestHolderAuthenticationFilter.java:49)
at grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter.doFilter(MutableLogoutFilter.java:82)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
为什么我会收到此异常?我在我的文件中包含了类RegisterCommand
(也在原始源中)?
我真的很感激你的意见!
更新
我改变了我的方法:
def index() {
def copy = [:] + (flash.chainedParams ?: [:])
copy.remove 'controller'
copy.remove 'action'
['controller', 'action', 'format'].each { copy.remove it }
[command: new RegisterCommand(copy)]
}
然而,现在我仍然无法处理注册,我得到:
....ui.SpringSecurityUiService problem creating Person: com.TestApp.auth.Person : (unsaved)
The property [firstName] of the type [class com.TestApp.auth.Person] cannot be null
The property [lastName] of the type [class com.TestApp.auth.Person] cannot be null
答案 0 :(得分:2)
format
在UrlMapping中添加为可选字段。
"/$controller/$action?/$id?(.$format)?"{
constraints {
// apply constraints here
}
}
因此,您最终会从action
和controller
中删除地图中的内容。
//index action
['controller', 'action', 'format'].each { copy.remove it }
另一种选择是明确使用bindData
来避免这种冲突
//index action
RegisterCommand cmd = new RegisterCommand()
bindData copy, cmd