Grails spring-security - 我可以在成功操作之前拦截以检查所需的密码更改吗?

时间:2011-10-27 23:01:47

标签: grails spring-security grails-plugin

在我的系统中创建新用户后,我通过电子邮件向他们发送临时密码,并设置changePasswordNextLogin = true属性。当他们第一次登录时,我想在成功登录后拦截流程,检查这个值,如果是,则将它们重定向到更改密码操作。密码更改完成后,理想情况下我希望将密码发送到预定目的地。

我一直在倾注默认设置并且没有看到 - 或者更可能没有正确解释 - 任何方式来实现这一点。似乎几乎每次我尝试在Grails中拼凑一些解决方案时,我发现有人已经做了一个更优雅的方法来做同样的事情。是否有内置的功能允许这样做?

如果没有,我会非常感谢有关最佳方法的任何建议。

2 个答案:

答案 0 :(得分:5)

有一些支持直接使用Spring Security和grails插件,但你还必须自己做一些工作:)

安装grails-spring-security插件(并运行S2Quickstart脚本)时创建的域类在其上有一个名为“passwordExpired”的属性。在创建新用户域实例时将其设置为true。

一旦该用户第一次登录,Spring Security核心库将抛出一个异常,您可以在登录控制器的authfail关闭中捕获该异常,将它们重定向到更改密码表单(您需要自己提供)

以下是我的某个应用程序的示例,此闭包的骨架版本应已包含在您的登录控制器中:

/**
 * Callback after a failed login.
 */
def authfail = {

    def msg = ''

    def username = 
       session[UsernamePasswordAuthenticationFilter.SPRING_SECURITY_LAST_USERNAME_KEY]

    def exception = session[WebAttributes.AUTHENTICATION_EXCEPTION]

    if (exception) {
        if (exception instanceof CredentialsExpiredException) {
            msg = g.message(code: "springSecurity.errors.login.passwordExpired")
            if (!springSecurityService.isAjax(request))
                redirect (action:'changePassword') // <-- see below
        }
        // other failure checks omitted
    }

    if (springSecurityService.isAjax(request)) {
        render([error: msg] as JSON)
    }
    else {
        flash.message = msg
        redirect controller: 'login', action:'auth', params: params
    }
}

/**
 * render the change pwd form
 */
def changePassword = {
    [username: session[UsernamePasswordAuthenticationFilter.SPRING_SECURITY_LAST_USERNAME_KEY] ?: springSecurityService.authentication.name]
}

从你的'changePasssword'视图中,将表单提交回另一个控制器闭包(我称之为'updatePassword',检查你想要的密码约束,并将更新后的密码保存在域对象上。

def updatePassword = {
    String username = session[UsernamePasswordAuthenticationFilter.SPRING_SECURITY_LAST_USERNAME_KEY] ?: springSecurityService.authentication.name
    if (!username) {
        flash.message = 'Sorry, an error has occurred'
        redirect controller: 'login', action:'auth'
        return
    }
    String password = params.password
    String newPassword = params.password_new
    String newPassword2 = params.password_new_2
    if (!password || !newPassword || !newPassword2 || newPassword != newPassword2) {
        flash.message = 'Please enter your current password and a new password'
        render view: 'changePassword', model: [username: username]
        return
    }
    SecUser user = SecUser.findByUsername(username)
    if (!passwordEncoder.isPasswordValid(user.password, password, null /*salt*/)) {
        flash.message = 'Current password is incorrect'
        render view: 'changePassword', model: [username: username]
        return
    }
    if (passwordEncoder.isPasswordValid(user.password, newPassword, null /*salt*/)) {
        flash.message = 'Please choose a different password from your current one'
        render view: 'changePassword', model: [username: username]
        return
    }
    if (!newPassword.matches(PASSWORD_REGEX)) {
        flash.message = 'Password does not meet minimum requirements'
        render view: 'changePassword', model: [username: username]
        return            
    }

    // success if we reach here!
    user.password = springSecurityService.encodePassword(newPassword)
    user.passwordExpired = false
    user.save() 

    flash.message = 'Password changed successfully' + (springSecurityService.loggedIn ? '' : ', you can now login')
    redirect uri: '/'
}

答案 1 :(得分:1)

如果您使用的是Spring Security 3.0及更高版本,则可以参考spring security插件文档11.3 Account Locking and Forcing Password Change。 请记住,你应该设置 Config.groovy中的grails.plugin.springsecurity.apf.storeLastUsername=true