Grails spring-security - Can I intercept before success action to check required password change?

别等时光非礼了梦想. 提交于 2019-12-04 19:35:01

There is some support for this directly with Spring Security and the grails plugin, but you also have to do some work yourself :)

The domain class that was created when you installed grails-spring-security plugin (and ran the S2Quickstart script) has a property on it named 'passwordExpired'. Set this to true when you create your new user domain instance.

Once that user logs in for the first time, the Spring Security core libs will throw an exception which you can catch in your login controller's authfail closure, re-directing them to the change password form (that you need to supply yourself).

Here's an example from one of my apps, a skeleton version of this closure should already be included in your login controller:

/**
 * 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]
}

From your 'changePasssword' view, submit the form back to another controller closure (I call mine 'updatePassword' that checks whatever constraints you want for passwords and either saves the updated password on the domain object or not..

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: '/'
}

If you are using Spring Secuirty 3.0 and later, You can refer to the spring security plugin documentation 11.3 Account Locking and Forcing Password Change. Remember that you should set grails.plugin.springsecurity.apf.storeLastUsername=true in Config.groovy.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!