精通 Grails: 身份验证和授权
身份验证
对于支持多个用户的博客服务器来说,进行身份验证是个好主意。您肯定不希望 John Doe 以 Jane Smith 的身份发布博客条目,不管是有意还是无意。设置身份验证基础设施将回答这个问题:“您是谁?”,稍后,您还将添加一些授权机制。授权将回答关于 “允许您做什么” 的问题。
清单 1 展示了您在 在上一篇文章 中创建的 grails-app/domain/User.groovy 文件:
清单 1. User 类
static constraints = {
login(unique:true)
password(password:true)
name()
}
static hasMany = [entries:Entry]
String login
String password
String name
String toString(){
name
}
}
login 和 password 字段已经就绪。您现在只需要提供一个控制器和一个表单。创建 grails-app/controllers/UserController.groovy 并添加如清单 2 所示的代码:
清单 2. 将 login、authenticate 和 logout 闭包添加到 UserController
def scaffold = User
def login = {}
def authenticate = {
def user = User.findByLoginAndPassword(params.login, params.password)
if(user){
session.user = user
flash.message = "Hello ${user.name}!"
redirect(controller:"entry", action:"list")
}else{
flash.message = "Sorry, ${params.login}. Please try again."
redirect(action:"login")
}
}
def logout = {
flash.message = "Goodbye ${session.user.name}"
session.user = null
redirect(controller:"entry", action:"list")
}
}
空的 login 闭包仅仅表示在您的浏览器中访问 http://localhost:9090/blogito/user/login 将呈现 grails-app/views/user/login.gsp 文件(您稍后即将创建该文件)。
authenticate 闭包使用了一个方便的 GORM 方法(findByLoginAndPassword() )执行需要的操作:在数据库中查找 User,该 User 的 login 和 password 匹配表单字段中输入的值,并通过 params hashmap 使用户可用。如果 User 存在的话,将它添加到会话中。如果不存在的话,重定向回登录表单以允许 User 再一次提供正确的凭证。logout 闭包将执行 User 退出,将他或她从会话中删除,然后重定向回 EntryController 中的 list 操作。
现在让我们开始创建 login.gsp。可以手动输入清单 3 中所示的代码,或者可以执行下面的操作:
在命令行输入 grails generate-views User。
将 create.gsp 复制到 login.gsp。
简化生成的代码。
清单 3. login.gsp
<head>
<meta name="layout" content="main" />
<title>Login</title>
</head>
<body>
<div class="body">
<h1>Login</h1>
<g:if test="${flash.message}">
<div class="message">${flash.message}</div>
</g:if>
<g:form action="authenticate" method="post" >
<div class="dialog">
<table>
<tbody>
<tr class="prop">
<td class="name">
<label for="login">Login:</label>
</td>
<td>
<input type="text" id="login" name="login"/>
</td>
</tr>
<tr class="prop">
<td class="name">
<label for="password">Password:</label>
</td>
<td>
<input type="password" id="password" name="password"/>
</td>
</tr>
</tbody>
</table>
</div>
<div class="buttons">
<span class="button">
<input class="save" type="submit" value="Login" />
</span>
</div>
</g:form>
</div>
</body>
</html>
注意,表单的 action 是 authenticate,它匹配 UserController.groovy 中的闭包的名称。输入元素( login 和 password )中的名称对应于 authenticate 闭包中的 params.login 和 params.password。
输入 grails run-app 并运行您的身份验证基础设施。尝试使用密码 foo 以 jsmith 的身份登录(记住在 “用定制 URI 和 codec 优化 Grails 中的 URI” 中,您在 grails-app/conf/BootStrap.groovy 中为 Blogito 提供了一些用户)。您的登录将失败,如图 1 所示:
图 1. 失败的登录尝试,显示错误消息

再次以 jsmith 的身份和密码 wordpass 尝试登录。这一次应当成功。
如果欢迎消息没有出现在 grails-app/views/entry/list.gsp 中 — 并且它不应该出现 — 那么只需将
图 2. 确认成功登录的 Flash 消息

现在可以确定身份验证能够正常工作,应当创建一个 TagLib 来简化登录和退出。