08 Adding authentication

簡介


現在,我們必須在管理系統須要加入一些認證機制。幸運的是,Play有一個模組。就是所謂的Secure module


Enabling the Secure module

啟用SECURE模組必須在yabe/conf/application.conf檔案新增以及重新啟動應用程式。

# Import the secure module module.secure=${play.path}/modules/secure

重新啟動之後,Play就會載入該模組套件了。Secure模組配置一組預設的路徑,你可以簡單地在yabe/conf/routes檔案設定(或者我們也可以自定義路徑):

# Import Secure routes * / module:secure


Protecting the admin controllers

該模組提供了一個Controllers。Secure controller聲明所有需要的攔截器。當然,我們可以只要繼承該Controllers,但是因為Java僅單一繼承,這會有些問題。為了不直接繼承Secure controller,我們可以在管理介面上使用註解並運用@With annotation告訴Play調用相對應的攔截器會更好。

package controllers; import play.*; import play.mvc.*; @With(Secure.class) public class Posts extends CRUD { }

在Comments, Users and Tags controllers也是一樣的做法。現在,如果你嚐試訪問任何管理介面,你都必須要經過登錄頁面:



Customizing the authentication process

應用程式必須提供一個已實例化Controllers。Secure.Security自定義身份驗證的過程。通過我們自己建立的Class,將能精確指定用戶進行身份驗證。此時,建立一個方法在yabe/controllers/Security.java檔案並Override authenticate()方法:

package controllers; import models.*; public class Security extends Secure.Security { static boolean authenticate(String username, String password) { return true; } }

正如我們已經有了User objects在Blog model,可以很容易地實現working version在該方法上。

static boolean authenticate(String username, String password) { return User.connect(username, password) != null; }

現在可以瀏覽http://localhost:9000/logout,你可以嘗試登入用戶從data.yml檔案中找尋使用者,例如:帳號密碼為bob@gmail.com/secret的這位使用者。


Refactoring the administration area

我們已經開始使用CRUD模組在管理者系統上,但是,它尚未得到很好的Blog UI介面。我們將開始在管理者系統上給予一個全新的介面。這個人可以給予其它作者權限來發表文章。並具有最大權限使用CRUD模組,此為超級使用者。讓我們為管理者系統建立一個Admin Controller:

package controllers; import play.*; import play.mvc.*; import java.util.*; import models.*; @With(Secure.class) public class Admin extends Controller { @Before static void setConnectedUser() { if(Security.isConnected()) { User user = User.find("byEmail", Security.connected()).first(); renderArgs.put("user", user.fullname); } } public static void index() { render(); } }

並定義路徑在yabe/conf/routes檔案中。

# Administration GET /admin/? Admin.index * /admin module:crud

現在將‘Log in to write something’ 加入超連結,該檔案位於yabe/app/views/main.html 模版。

... <ul id="tools"> <li> <a href="@{Admin.index()}">Log in to write something</a> </li> </ul> ...

最後,為了讓這些程序運行起來我們要建立yabe/app/views/Admin/index.html模版。先從最簡單的開始:

Welcome ${user}!

現在,進入Blog首頁,點擊 ‘Log in to write something’,你應該會前往新的管理者系統介面:


看來相當不錯!!但是,因為我們將在這幾頁操作管理介面,我們需要一個超級模版(super-template)。讓我們建立一個檔案在yabe/app/views/admin.html

<!DOCTYPE html> <html> <head> <title>Administration</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> #{get 'moreStyles' /} <link rel="stylesheet" type="text/css" media="screen" href="@{'/public/stylesheets/main.css'}" /> <link rel="shortcut icon" type="image/png" href="@{'/public/images/favicon.png'}" /> <script src="@{'/public/javascripts/jquery-1.3.2.min.js'}"></script> <script src="@{'/public/javascripts/jquery.tools.min.js'}"></script> </head> <body id="admin"> <div id="header"> <div id="logo"> yabe. <span>administration</span> </div> <ul id="tools"> <li> <a href="@{Secure.logout()}">Log out</a> </li> </ul> </div> <div id="main"> #{doLayout /} </div> <p id="footer"> Yabe is a (not so) powerful blog engine built with the <a href="http://www.playframework.org">Play framework</a> as a tutorial application. </p> </body> </html>

正如你所看到的,你已經取代了登入超連結來調用Secure controller的登出 action所調用的secure module。現在,讓我們使用yabe/app/views/Admin/index.html模版並重新整理:

#{extends 'admin.html' /} Welcome ${user}!



如果你嘗試登出連結將會返回至登入頁面:


這是預設當secure module登出所處理的事件。但是,它很容易制定簡單地通過覆寫onDisconnected()方法在controllers.Security class

static void onDisconnected() { Application.index(); }

你也可以同樣去做onAuthenticated()事件:

static void onAuthenticated() { Admin.index(); }


Adding roles

其實,我們需要兩組管理者介面:一個是簡單的編輯器,另一個是超級管理者。正如你所看到User model有一個isAdmin欄位來定義用戶是否具有超級管理者權限。該Secure module不僅提供了身份驗證,也授權管理。這就是所謂的profiles。要建立一個Admin profiles, 你必須Override check()方法在controllers.Security class之中:

static boolean check(String profile) { if("admin".equals(profile)) { return User.find("byEmail", connected()).<User>first().isAdmin; } return false; }

現在,我們可以顯示出管理選單,如果用戶具有管理者角色的話。更新yabe/views/admin.html並整合選單在頂層:

... <div id="main"> <ul id="adminMenu"> <li class="${request.controller == 'Admin' ? 'selected' : ''}"> <a href="@{Admin.index()}">My posts</a> </li> #{secure.check 'admin'} <li class="${request.controller == 'Posts' ? 'selected' : ''}"> <a href="@{Posts.list()}">Posts</a> </li> <li class="${request.controller == 'Tags' ? 'selected' : ''}"> <a href="@{Tags.list()}">Tags</a> </li> <li class="${request.controller == 'Comments' ? 'selected' : ''}"> <a href="@{Comments.list()}">Comments</a> </li> <li class="${request.controller == 'Users' ? 'selected' : ''}"> <a href="@{Users.list()}">Users</a> </li> #{/secure.check} </ul> #{doLayout /} </div> ...

注意,我們要知道如何使用 #{secure.check /} tag來顯示只有管理者才會出現的選單。



但是,這還不夠。如果使用者知道URL他仍然可後隨意訪問。我們必須保護該Controllers會更好。我們必須使用@Check annotation。例如,在Posts controllers上:

package controllers; import play.*; import play.mvc.*; @Check("admin") @With(Secure.class) public class Posts extends CRUD { }

一樣的方式可以在Tags, Comments及Users controllers上運用。現在嘗試用一般用戶重新登入(如: jeff@gmail.com/secret)。你應該不會看到CRUD admin超連結才對。如果你嘗試強制訪問http://localhost:9000/admin/users 你應該會得到一個403回應。




Customizing the CRUD layout


這很有趣,但是當我們前往CRUD的管理者介面,我們失去了管理介面佈局。這是因為CRUD模組提供了自己的佈局。但是,我們一樣可以自定義佈局。必須使用以下的Play指令:

play crud:ov --layout

你將會得到一組模版在yabe/app/views/CRUD/layout.html。讓我們來取代它的內容來建置我們自己的佈局:

#{extends 'admin.html' /} #{set 'moreStyles'} <link rel="stylesheet" type="text/css" media="screen" href="@{'/public/stylesheets/crud.css'}" /> #{/set} <div id="crud"> #{if flash.success} <div class="crudFlash flashSuccess"> ${flash.success} </div> #{/if} #{if flash.error || error} <div class="crudFlash flashError"> ${error ?: flash.error} </div> #{/if} <div id="crudContent"> #{doLayout /} </div> </div>

正如你所看見的,我們運用crud.css及admin.html使用了get/set模版變數機制。現在,如果你嘗試運行CRUD的管理者介面,就會有管理者介面的佈局出現:




Styling the login page

該管理者介面幾乎要一致的。最後,要設計登入頁面的CSS風格。我們可以簡單地自定義並覆寫預設的CSS:

play secure:ov --css

我們保留了CSS,但是必須在最上層import main.css在yabe/public/stylesheets/secure.css

@import url(main.css); ...


並自定義登入畫面訊息,增加相關訊息於yabe/conf/messages檔案中:

secure.username=Your email: secure.password=Your password: secure.signin=Log in now



Comments