上篇介紹了 Filter 的使用以及 Django 的作法,這篇我們就來試著簡化 Django 的作法,然後參考官方文件,來實作一個在驗證失敗後會導向到 /login 的 Filter。
先回頭複習一下 migration,先建立 model
bee generate model Member -fields="username:string,password:string" -driver="mysql"
然後再建立 migration
bee generate migration user -fields="name:string,gender:string,birthday:datetime"
bee migrate
用 MySQL CLI 新增一筆資料,密碼部份先暫時使用明碼。
mysql
mysql> use hellodb;
mysql> insert into member (username, password) values ('johndoe', 'his_password');
接著實作登入頁面
bee generate controller login
編輯 controllers/login.go
package controllers
import (
"html/template"
"my/hello/models"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
)
// LoginController operations for Login
type LoginController struct {
beego.Controller
}
// Post ...
// 處理登入
func (c *LoginController) Post() {
c.TplName = "login/index.tpl"
c.Data["has_error"] = false
// Check XSRF first.
if !c.CheckXSRFCookie() {
c.Data["error"] = "XSRF token missing or incorrect."
c.Data["has_error"] = true
return
}
// parse form parameters
username := c.GetString("username")
password := c.GetString("password")
// 以 username 去找使用者
o := orm.NewOrm()
v := &models.Member{Username: username}
// 沒有找到,顯示錯誤
c.Data["error"] = "No such member."
c.Data["has_error"] = true
return
}
// 找到使用者,檢查密碼
if password == v.Password {
// 在 session 留下 user_id,作為檢查依據
// 這是簡便作法,實務上要嚴謹
c.SetSession("user_id", int(v.Id))
} else {
c.Data["error"] = "Authentication fail."
c.Data["has_error"] = true
return
}
c.Ctx.Redirect(302, "/myuser/")
}
// Get ...
// 顯示登入表單
func (c *LoginController) Get() {
c.Data["has_error"] = false
c.Data["xsrfdata"] = template.HTML(c.XSRFFormHTML())
c.TplName = "login/index.tpl"
}
在 router 裡加入登入頁面的路由
beego.Router("/login", &controllers.LoginController{}, "get:Get")
beego.Router("/login", &controllers.LoginController{}, "post:Post")
跟登入一樣,先產生登出的 controller
bee generate controller logout
然後編輯 controllers/logout.go
package controllers
import (
"github.com/astaxie/beego"
)
// LogoutController operations for Logout
type LogoutController struct {
beego.Controller
}
// Get
func (c *LogoutController) Get() {
c.DelSession("user_id")
c.Data["has_error"] = false
c.TplName = "logout/index.tpl"
}
同樣也在 routers/router.go 裡加入登出頁面的路由
beego.Router("/logout", &controllers.LogoutController{}, "get:Get")
終於到 Filter 的部份了,Filter 裡就只是簡單的檢查 user_id,如果沒有,就導向到登入頁。
var FilterMember = func(ctx *context.Context) {
if strings.HasPrefix(ctx.Input.URL(), "/login") {
return
}
_, ok := ctx.Input.Session("user_id").(int)
if !ok {
ctx.Redirect(302, "/login")
}
}
這邊要照 Django 的方法走的話,還需要埋入 user,這樣後續的 Controller 就可以直接判斷或使用。
好,Filter 寫好,接著就來安插進去使用
beego.InsertFilter("/myuser/*", beego.BeforeRouter, FilterMember)
好,到這裡,也差不多完工了。對了,模版的程式碼我省略囉,完整的程式請到 github 上看。