Grails grants you the ability to quickly define dynamic codecs that you can easily call from within your Grails app. One of the most common uses of a such codecs in web applications is the creation of one-way hashed password strings. Grails makes this very easy to implement and use.
First, create a new codec in /grails-app/utils.
/grails-app/utils/PasswordCodec.groovy:
import java.security.MessageDigest
import sun.misc.BASE64Encoder
import sun.misc.CharacterEncoder
class PasswordCodec {
static encode = { str ->
MessageDigest md = MessageDigest.getInstance('SHA')
md.update(str.getBytes('UTF-8'))
return (new BASE64Encoder()).encode(md.digest())
}
}
You only need to define the encode closure (codecs may also have a decode closure, but you don't need one for a one-way hash). The above encode closure accepts a string parameter (str). It then creates a SHA-1 MessageDigest to digest the string. The digested string (an array of bytes) is handed off to a Base64Encoder to turn it into the returned encoded hashed string.
You may now call this codec on any string in your grails appplication by calling someString.encodeAsPassword(). Here is a complete user controller (modified from the one in Grails - The Definitive Guide, pgs. 159-167) that uses the PasswordCodec to encode the password when the user registers and to compare an entered password with a stored password when the user logs in.
/grails-app/controllers/UserController.groovy:
class UserController {
def login = {
if (session.user) {
redirect(controller:'topic', action:'list')
}
}
def handleLogin = {
def user = User.findByEmail(params.email)
if (user) {
if (user.password == params.password.encodeAsPassword()) {
session.user = user
redirect(controller:'topic', action:'list')
}
else {
flash.message = "Incorrect password for ${params.email}"
redirect(action:login)
}
}
else
{
flash.message = "User not found for email ${params.email}"
redirect(action:login)
}
}
def register = {}
def handleRegistration = {
def user = new User(params)
if (params.password != params.confirm) {
flash.message = "The passwords you entered do not match."
redirect(action:register)
}
else {
user.password = params.password.encodeAsPassword()
if (user.save()) {
redirect(controller:'topic', action:'list')
}
else
{
flash.user = user
redirect(action:register)
}
}
}
}