技术开发 频道

精通 Grails: 身份验证和授权

  身份验证

  对于支持多个用户的博客服务器来说,进行身份验证是个好主意。您肯定不希望 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 中所示的代码,或者可以执行下面的操作:

  在命令行输入 grails generate-views User。

  将 create.gsp 复制到 login.gsp。

  简化生成的代码。

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

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

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

0
相关文章