我正在尝试自定义spring security ui插件。我想要实现的目标:
1)管理员使用来自spring security ui的电子邮件创建一个新用户
2)应用生成链接并将其发送到用户的电子邮件
3)用户点击链接并查看可以指定密码并保存的页面
4)用户提交页面帐户后,使用他指定的密码激活
为此,我决定默认自定义由Spring安全性UI提供的UserController:
class UserController extends grails.plugin.springsecurity.ui.UserController {
def mailService
def save() {
def user = lookupUserClass().newInstance(params)
if (!user.save(flush: true)) {
render view: 'create', model: [user: user, authorityList: sortedRoles()]
return
}
//generate secured link
def registrationCode = new RegistrationCode(username: user.username).save(flush: true)
String url = generateLink('verifyRegistration', [t: registrationCode.token])
def conf = SpringSecurityUtils.securityConfig
//here we should send an invitation mail
mailService.sendMail {
async true
to user.email
from conf.ui.register.emailFrom
subject conf.ui.register.emailSubject
html url
}
addRoles(user)
flash.message = "${message(code: 'default.created.message', args: [message(code: 'user.label', default: 'User'), user.id])}"
redirect action: 'edit', id: user.id
}
def verifyRegistration() {
def conf = SpringSecurityUtils.securityConfig
String defaultTargetUrl = conf.successHandler.defaultTargetUrl
String token = params.t
println token
def registrationCode = token ? RegistrationCode.findByToken(token) : null
if (!registrationCode) {
println registrationCode
flash.error = message(code: 'spring.security.ui.register.badCode')
redirect uri: defaultTargetUrl
return
}
render(view: "initpassword", model: [token: token])
}
def savePassword() {
String token = params.token
def conf = SpringSecurityUtils.securityConfig
String defaultTargetUrl = conf.successHandler.defaultTargetUrl
def registrationCode = token ? RegistrationCode.findByToken(token) : null
//TODO check if passwords are equal
if (!registrationCode) {
flash.error = message(code: 'spring.security.ui.register.badCode')
redirect uri: defaultTargetUrl
return
}
def user
RegistrationCode.withTransaction { status ->
String usernameFieldName = SpringSecurityUtils.securityConfig.userLookup.usernamePropertyName
user = lookupUserClass().findWhere((usernameFieldName): registrationCode.username)
if (!user) {
return
}
user.accountLocked = false
String salt = saltSource instanceof NullSaltSource ? null : params.username
user.password = springSecurityUiService.encodePassword(params.password1, salt)
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
}
}
}
和initpassword.gsp非常简单,如下所示:
<g:form action="savePassword" absolute="true" method="POST">
<g:passwordField name="password1"/>
<g:passwordField name="password2"/>
<g:hiddenField value="${token}" name="token"/>
<g:actionSubmit value="Save"/>
</g:form>
到目前为止一切看起来都很好(至少对我来说,如果你发现错误的话,请告诉我)但是当我尝试测试它时会发生非常奇怪的事情:
1)我点击了电子邮件中发送的链接(调用了verifyRegistration()方法)
2)应用程序显示此页面,我可以输入密码(显示initpassword页面)
3)我提交页面(这里应该调用savePassword()但由于某种原因它没有被调用)和app显示我从spring security ui插件创建一个新用户的默认页面,其中包含验证错误,其中表示字段为用户(一个一个)不能为空
4)当我尝试调试(在savePassword()方法的开头使用断点)没有任何反应 - 似乎控制器只是没有捕获对savePassword()的请求
但是当我尝试从浏览器中打开savePassword()方法(输入localhost / myApp / user / savePassword)时,控制器捕获请求并对该断点进行调试。
我花了近4个小时处理这件事。不知道究竟发生了什么。与Grails有些神奇。 有人可以帮我弄这个吗?谢谢!!!
答案 0 :(得分:1)
在initpassword.gsp
中,只需将action="savePassword"
属性添加到g:actionSubmit
标记即可。您甚至可以从g:form
标记中删除此属性。这就是Grails在表单中拥有多个动作的能力。我不确定,但在干净的HTML中,它也可能有效。
<html>
<head>
<title></title>
</head>
<body>
<g:form controller="user" absolute="true" method="POST">
<g:passwordField name="password1"/>
<g:passwordField name="password2"/>
<g:hiddenField value="${token}" name="token"/>
<g:actionSubmit value="Save" action="savePassword"/>
</g:form>
</body>
</html>