本小节实现登录功能。在本小节,读者还将学习到 Filter 的用法和 uitls 的用法。
首先创建用于登录的 Domain Class,在控制台输入:
grails create-domain-class Users |
然后修改 Domain Class 的内容如下:
class Users { String username String password static constraints = { username(size:5..60,blank:false,unique:true) password(size:5..60,blank:false) } }
|
相信读者一定不希望将密码的名文直接保存到数据库中。这里就涉及一个 SHA 的加密过程,Grails 希望我们在 utils 中实现这个过程。在 grails-app/utils 中创建一个名为 PasswordCodec
的 Groovy 类(强调一下类名必需是 XXXCodec),编写代码如下:
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()) } }
|
接下来我们写程序让应用启动时自动往 Users 表添加一条记录。BootStrap
类可以帮助我们实现这个功能,修改 grails-app/config/BootStrap.groovy 的代码:
class BootStrap { def init = { servletContext -> def user = new Users(id:1,username:'liangshixing' ,password:'liangshixing') user.password = user.password.encodeAsPassword() user.save() } def destroy = { } }
|
BootStrap
类中的 init
闭包中的代码将在启动时首先执行。这里我们创建了一个 Users 对象,并为它初始化了用户名和密码。
这里要注意一点,user.password.encodeAsPassword()
正是源于我们创建的 Utils 类,Grails 会根据命名约定,查找并执行 PasswordCodec
类的 encode
闭包,从而实现了 SHA 的加密。
Utils 类也是 Grails 的约定编码的一个典泛。
接下来实现表单页面和 Controller(可以先使用 generate-all,然后在自动生成的代码上改),这里仅摘录 Controller 的代码:
class UsersController { def index = { redirect(action:login,params:params) } def login = { def users = new Users() users.properties = params return ['users':users] } def loginCheck = { def users = new Users(params) if(!users.hasErrors()) { users.password = params.password.encodeAsPassword() def resultUsers=Users.findByUsernameAndPassword(users.username,users.password) if(resultUsers) { session.user = resultUsers redirect(controller:'member',action:'search') } else { flash.message = 'Login failed: incorrect username and password' render(view:'login',model:[users:users]) } } else { render(view:'login',model:[users:users]) } } def logOut = { session.invalidate() redirect(controller:'users',action:'login') } }
|
login
Action 会跳转到 login.gsp,用于显示登录的表单页面。
loginCheckAction
将检查用户名密码是否正确。如果正确,则将 Users 对象保存到 session 中,然后重定向到搜索 member 的页面;如果不正确,报错并要求重新登录。
logOut
调用 session 的 invalidate
方法,可以清空 session。然后调用 redirect
从定向到登录页面。
登录登出的功能已经实现了,但我们的应用还没有被保护起来,Filter 可以帮助实现这个功能(Grails1.0rc1 中第一次支持这个功能)。
首先在 grails-app/config/ 文件夹中创建一个名为 LoginFilters
的类(类名必须以 Filters 结尾)。编写如下代码:
class LoginFilters { def filters = { loginCheck(controller:'*', action:'*') { before = { if(!session.user) { if(!actionName.equals('login') && !actionName.equals('logOut') && !actionName.equals('loginCheck') && !actionName.equals('list') && !actionName.equals('search') && !actionName.equals('show')) { redirect(controller:'users',action:'login') return false } } } } } }
|
Filters
类中可以使用 actionName
和 controllerName
去获取 action 和 controller 的名称。本文例子中的限制只有 login,logOut,loginCheck,list,search,show 不需要登录,如果访问其它页面,都需要登录。