Go語言WEB框架:使用wego攔截器驗證使用者的登入狀態

haming 發表於 2022-07-18
框架 Go

wego攔截器

wego攔截器是一個action(處理器函式)之前或之後被呼叫的函式,通常用於處理一些公共邏輯。攔截器能夠用於以下常見問題:

  • 請求日誌記錄
  • 錯誤處理
  • 身份驗證處理

wego中有以下攔截器:

  • before_exec :執行action之前攔截器
  • after_exec :執行action之後攔截器

本文用一個例子來說明如何使用攔截器來實現使用者登入狀態的判定。在這個例子中,使用者訪問login_get來顯示登入頁面,並呼叫login_post頁面來提交登入資訊。在login_post頁面中判定使用者登入資訊是否合法,並將登入賬號儲存在session中。使用者訪問其他需要登入驗證的頁面(例如:index頁面)前首先執行攔截器:handler.BeforeExec。在攔截器中獲取使用者賬號,若沒有獲取到使用者賬號,則跳轉到登入頁面:login_get。使用攔截器來進行使用者登入狀態的檢查的有點是,不用在每個處理器函式中都包含使用者登入狀態的檢查邏輯。只要將登入邏輯獨立出來,並實現為before_exec攔截器即可。以下時main函式的主要內容:

main函式

package main
import (
    "demo/handler"
    "github.com/haming123/wego"
    log "github.com/haming123/wego/dlog"
)
func main() {
    web, err := wego.InitWeb()
    if err != nil {
        log.Error(err)
        return
    }
    
    wego.SetDebugLogLevel(wego.LOG_DEBUG)
    web.Config.SessionParam.SessionOn = true
    web.Config.SessionParam.HashKey = "demohash"

    web.BeforExec(handler.BeforeExec)
    web.GET("/login_get", handler.HandlerLoginGet).SkipHook()
    web.POST("/login_post", handler.HandlerLoginPost).SkipHook()
    web.GET("/index", handler.HandlerIndex)

    err = web.Run("0.0.0.0:8080")
    if err != nil {
        log.Error(err)
    }
}

說明:

  • 本例子中使用基於cookie的session資料儲存引擎,用於儲存使用者登入賬號。
  • 呼叫web.BeforExec(handler.BeforeExec)來設定攔截器,在handler.BeforeExec攔截器中實現了登入狀態的檢查邏輯。
  • 由於login_get頁面、login_post頁面不需要進行登入檢驗,使用SkipHook()來忽略攔截器。

登入邏輯

使用者訪問需要進行登入驗證的頁面時,首先會檢查session的登入賬號,若沒有登入賬號,則跳轉到登入頁面:login_get, 登入頁面的處理器實現如下:

func HandlerLoginGet(c *wego.WebContext) {
    c.WriteHTML(http.StatusOK, "./view/login.html", nil)
}

login.html的內容如下:

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>登入頁面</title>
</head>
<body>
<h2>使用者登陸</h2>
<form action="/login_post" method="post">
    <div>使用者賬號:</div>
    <div>
        <input type="text" name="account" placeholder="請輸入使用者賬號" />
    </div>
    <br />
    <div>登入密碼:</div>
    <div>
        <input type="password" name="password" placeholder="請輸入登入密碼"/>
    </div>
    <br />
    <div>
        <input type="submit" value="立即登入" />
    </div>
</form>
</body>
</html>

使用者點選"立即登入"後項伺服器傳送post請求到login_post, login_post處理器的實現如下:

func HandlerLoginPost(c *wego.WebContext) {
    account := c.Param.MustString("account")
    password := c.Param.MustString("password")
    if account == "admin" && password == "demo" {
        c.Session.Set("account", account)
        c.Session.Save()
        c.Redirect(302, "/index")
    } else {
        c.Session.Set("account", "")
        c.Session.Save()
        c.Redirect(302, "/login_get")
    }
}

說明:

  • 在HandlerLoginPost呼叫c.Session.Set將賬號寫入session。

登入攔截器的實現

登入檢查的邏輯採用before_exec攔截器來實現,以下是before_exec攔截器的程式碼:

func GetAccount(c *wego.WebContext) string {
    account, _ := c.Session.GetString("account")
    return account
}
func BeforeExec(c *wego.WebContext) {
    login_path := "/login_get"
    if GetAccount(c) == "" && c.Path != login_path {
        c.Redirect(302, login_path)
        return
    }
}

說明:

  • 實現GetAccount函式來獲取session資料,若使用者成功登入了系統,則session中儲存有使用者的登入賬號。在處理器函式中可以呼叫GetAccount函式來獲取登入的登入賬號。
  • BeforeExec函式是before_exec攔截器的一個實現。在BeforeExec函式中首先呼叫GetAccount函式來獲取登入的登入賬號,若不存在使用者賬號,則跳轉到登入頁面:login_get,否則執行處理去函式。

index頁面的實現

index頁面需要驗證使用者是否登入,由於執行index頁面的處理器前會執行before_exec攔截器, 因此在index頁面的處理器函式中不需要再進行登入檢查了,程式設計師只需要實現業務邏輯即可。index頁面的處理器函式的實現程式碼如下:

func HandlerIndex(c *wego.WebContext) {
    c.WriteHTML(http.StatusOK, "./view/index.html", GetAccount(c))
}

在HandlerIndex中讀取index.html模板,並使用呼叫 GetAccount(c)獲取使用者賬號,然後及進行渲染。其中index.html模板的內容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
hello : {{.}}
</body>
</html>

wego程式碼的下載

go get github.com/haming123/wego