天天看點

Go語言實戰 - revel架構教程之權限控制

一個站點上面最基本都會有三種使用者角色,未登入使用者、已登入使用者和管理者。這一次我們就來看看在revel架構下如何進行權限控制。

因為revel是MVC結構的,每一個url其實都會映射到一個具體的Controller.Action上面,是以權限控制落到實處就是對Action的通路進行控制。

那麼思路是如下:

1. 有一個方法能夠判定目前是什麼角色。

2. 有一地方定義了每一個Action的通路權限要求。

3. 有一個方法能夠在調用所有Action之前被調用,而且能夠判定是否還要繼續調用Action。

我們一項一項來解決。

存儲目前使用者的角色資訊

先定義一個角色類型如下。

type Role int

const (

  AnonymousRole Role = iota

  UserRole

  AdminRole

)

 定義個常量,用于在session裡面存放目前使用者的角色類型。

const (

  CSessionRole = "CSessionRole"

然後在處理使用者登陸的方法中在session裡儲存角色資訊。

func (c *Account) HandleLogin(email, password string) revel.Result {

  //在這裡處理登陸邏輯

  c.Session[CSessionRole] = UserRole

  //在這裡處理跳轉和頁面渲染

}

func (c *Account) HandleAdminLogin(account, password string) revel.Result {

  c.Session[CSessionRole] = AdminRole

我們現在可以從session中讀取CSessionRole的值來判定目前使用者是什麼角色了。

定義Action的通路權限

在Controller層定義一個map,用于存放action的權限資訊,如下。

func initAuthMap() {

  authMap = make(map[string]Role)

  authMap["account.login"] = AnonymousRole

  authMap["account.logout"] = UserRole

  authMap["admin.index"] = AdminRole

要注意的是initAuthMap需要在Controller包的init函數中調用,以進行權限控制初始化。

檢查通路權限

revel架構提供的InterceptFunc(攔截方法)能夠将一個方法注入到所有Action的調用之前或之後,這就給權限控制留出了空間。

讓我們先定義一個方法用于檢查權限。

func checkAuthentication(c *revel.Controller) revel.Result {

  //擷取目前登陸使用者的角色資訊

  userRole, isExists := c.Session[util.CSessionRole]

  if !isExists {

    userRole = AnonymousRole

  }

  //擷取緊接着要調用的Action的名稱

  action := strings.ToLower(c.Action)

  //擷取相關action的權限定義

  if requiredRole, isExists = authMap[action]; isExists {

    //判斷權限,如果權限要求不相符

    if requiredRole != userRole {

      //跳轉到首頁

      return c.Redirect((*Application).Index)

    }

  //傳回nil表示可以接着調用後面的Action,在這裡就代表有權限通路

  return nil

将這個InterceptFunc注冊到revel的處理鍊中。

revel.InterceptFunc(checkAuthentication, revel.BEFORE, revel.ALL_CONTROLLERS)

好了,一個簡單的權限控制系統做好了。這裡隻是展現了最基本的概念和建構的思路,掌握了之後,就算面對再複雜的要求也可以通過擴充其中的一個部分去滿足。

另外,在我們的項目山坡網裡,由于authMap定義了超過50個Action,很多時候一旦Action名字更改了就可能導緻權限控制失效,針對這個問題,可以通過下面方法來解決。

authMap之前是用string做key,改成用reflect.Type就好了,注冊的時候這麼寫。

authMap[reflect.TypeOf((*Account.HandleLogin)(nil)] = AnonymousRole

這樣就可以用編譯器幫助檢查錯誤。

最後還得提一句,目前山坡網的Go代碼已經超過兩萬行,且運作良好。revel是個好架構,值得信賴。