精通 Grails: 身份验证和授权

来源:developerWorks 中国 作者:Scott Davis
  
Grails 提供了组成安全 Web 应用程序所需的所有基本构建模块,包括从简单的登录基础设施到基于角色的授权等各种组件,在本期的 精通 Grails 中,Scott Davis 帮助您通过动手操作保护 Grails 应用程序。您还将了解一些插件,可以帮助您以不同的方式扩展应用程序的安全功能。

在本文中,我将继续构建一个“微型博客” Blogito。我删除了此前文章(“用定制 URI 和 codec 优化 Grails 中的 URI”)中的 User,因为 name 字段是 URI 的重要组成部分。这一次我们将实现完整的 User 子系统。您将理解到如何根据 User 是否登录启用登录、限制用户行为,甚至根据 User 的角色添加一些授权。

首先,User 需要一种登录方式,从而能够发布新的条目。

身份验证

对于支持多个用户的博客服务器来说,进行身份验证是个好主意。您肯定不希望 John Doe 以 Jane Smith 的身份发布博客条目,不管是有意还是无意。设置身份验证基础设施将回答这个问题:“您是谁?”,稍后,您还将添加一些授权机制。授权将回答关于 “允许您做什么” 的问题。

清单 1 展示了您在 在上一篇文章 中创建的 grails-app/domain/User.groovy 文件:


清单 1. User 类
				
class 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
				
class 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 中所示的代码,或者可以执行下面的操作:

  1. 在命令行输入 grails generate-views User。
  2. 将 create.gsp 复制到 login.gsp。
  3. 简化生成的代码。

 


清单 3. login.gsp
				
<html>
  <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 中 — 并且它不应该出现 — 那么只需将 <g:if test="${flash.message}"> 块从 login.gsp 复制到 list.gsp 文件的顶部。再次以 jsmith 身份登录,检验现在是否显示了如图 2 所示的消息:


图 2. 确认成功登录的 Flash 消息

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





创建一个身份验证 TagLib

像 Google 和 Amazon 这样的 Web 站点在标题处提供了一个不太显眼的文本链接,允许您登录和退出。您只需要几行代码就可以在 Grails 中实现这一点。

首先,在命令提示下输入 grails create-tag-lib Login。将清单 4 中的代码添加到新创建的 grails-app/taglib/LoginTagLib.groovy 中:


清单 4. LoginTagLib.groovy
				
class LoginTagLib {
  def loginControl = {
    if(session.user){
      out << "Hello ${session.user.name} "
      out << """[${link(action:"logout", controller:"user"){"Logout"}}]"""
    } else {
      out << """[${link(action:"login", controller:"user"){"Login"}}]"""      
    }
  }
}

现在,将新的 <g:loginControl> 标记添加到 grails-app/views/layouts/_header.gsp,如清单 5 所示:


清单 5. 将 <loginControl> 标记添加到标题
				
<div id="header">
  <p><g:link class="header-main" controller="entry">Blogito</g:link></p>
  <p class="header-sub">A tiny little blog</p>
  
  <div id="loginHeader">
    <g:loginControl />
  </div>
</div>

最后,将针对 loginHeader <div> 的一些 CSS 格式添加到 web-app/css/main.css,如清单 6 所示:


清单 6. loginHeader <div> 的 CSS 格式
				
#loginHeader {
  float: right;
  color: #fff;
}

重启 Grails 并以 jsmith 身份登录后,屏幕应该如图 3 所示:


图 3. 实际使用 Login TagLib



时间:2009-06-19 11:05 来源:developerWorks 中国 作者:Scott Davis 原文链接

好文,顶一下
(0)
0%
文章真差,踩一下
(0)
0%
------分隔线----------------------------


把开源带在你的身边-精美linux小纪念品
无觅相关文章插件,快速提升流量