grails - spring security UI奇怪的行为

时间:2014-07-11 15:03:44

标签: grails grails-plugin grails-controller

我正在尝试自定义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有些神奇。 有人可以帮我弄这个吗?谢谢!!!

1 个答案:

答案 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>