上一篇里完成了短信驗(yàn)證碼的生成,這一篇里就完成短信驗(yàn)證碼的校驗(yàn)堰怨,以及后續(xù)的登錄和注冊(cè)功能
model
login.go
type Login struct {
Mobile string
Vcode string
}
登錄的model,需要手機(jī)號(hào)和短信驗(yàn)證碼
user.go
type User struct {
Id int64
Mobile string `orm:"size(11)"`
Type int `orm:"size(1)"`
}
func init() {
orm.RegisterModel(new(User))
}
// 根據(jù)手機(jī)號(hào)獲取或注冊(cè)用戶
func GetUserByMobile(mobile string) (id int64, err error) {
o := orm.NewOrm()
user := User{Mobile: mobile}
_, id, err = o.ReadOrCreate(&user, "Mobile")
return id, err
}
此處涉及到orm的問題了蛇摸,眾所周知备图,與orm的話寫代碼會(huì)方便很多,性能沒達(dá)到瓶頸的話orm還是很好用的
Id字段生成數(shù)據(jù)庫時(shí)會(huì)自動(dòng)變?yōu)橹麈I和自增,不要相信golint的鬼話寫成ID
orm.RegisterModel(new(User))
這句放在init函數(shù)中用來在一開始注冊(cè)模型
ReadOrCreate()
嘗試從數(shù)據(jù)庫讀取揽涮,不存在的話就創(chuàng)建一個(gè),這樣當(dāng)用戶沒有注冊(cè)的話就相當(dāng)于直接注冊(cè)了砸烦,該函數(shù)返回值分別為是否是新創(chuàng)建的,創(chuàng)建的id绞吁,錯(cuò)誤
自動(dòng)生成數(shù)據(jù)庫
main.go
func init() {
// set default database
orm.RegisterDataBase("default", "mysql", beego.AppConfig.String("sqlconn"), 30)
// create table
orm.RunSyncdb("default", false, true)
}
在main.go的init中設(shè)計(jì)數(shù)據(jù)庫的連接和自動(dòng)創(chuàng)建表
beego.AppConfig.String
會(huì)讀取config/app.conf
中的配置文件
orm.RunSyncdb("default", false, true)
設(shè)置創(chuàng)建表的規(guī)則,三個(gè)參數(shù)分別為數(shù)據(jù)庫別名唬格,是否先drop再建表家破,是否打印執(zhí)行過程
運(yùn)行的時(shí)候就會(huì)看到如圖所示的建表語句
controller
// @Title Login
// @Description 登錄
// @Param body body models.Login true "登錄信息"
// @Success 200 {int} 用戶id
// @Failure 400 {string} 驗(yàn)證碼錯(cuò)誤
// @Failure 500 {string} 服務(wù)器錯(cuò)誤
// @router / [post]
func (l *LoginController) Post() {
var login models.Login
json.Unmarshal(l.Ctx.Input.RequestBody, &login)
vcode := string(models.Redis.Get(login.Mobile).([]byte))
if login.Vcode != vcode {
l.Data["json"] = "驗(yàn)證碼錯(cuò)誤"
l.Abort("400")
}
id, err := models.GetUserByMobile(login.Mobile)
if err != nil {
l.Data["json"] = err.Error()
l.Abort("500")
}
l.SetSession("uid", id)
l.Data["json"] = id
l.ServeJSON()
}
使用string(models.Redis.Get(login.Mobile).([]byte))
來獲取存儲(chǔ)在redis中的驗(yàn)證碼,此處有坑,redis封裝的get取出來是個(gè)interface{},需要先轉(zhuǎn)成字節(jié)數(shù)組购岗,再轉(zhuǎn)成字符串才能用汰聋,你說這玩意整的
models.GetUserByMobile
查詢用戶是否存在,不存在則創(chuàng)建一個(gè)
SetSession
用來記錄登錄態(tài)喊积,單機(jī)版的直接就用session就好烹困,response里會(huì)帶著setcookie命令
router
beego.NSNamespace("/login",
beego.NSInclude(
&controllers.LoginController{},
),
),
效果
驗(yàn)證登錄態(tài)
還有很重要的一步就是登錄了之后要驗(yàn)證登錄態(tài),這個(gè)涉及的東西就比較復(fù)雜了,需要用過濾器來實(shí)現(xiàn)
main.go
var FilterUser = func(ctx *context.Context) {
_, ok := ctx.Input.Session("uid").(int64)
if !ok {
var whiteMap map[string]int
whiteMap = make(map[string]int)
whiteMap["/v1/login"] = 1
whiteMap["/v1/captcha"] = 1
whiteMap["/v1/sms"] = 1
if _, ok = whiteMap[ctx.Request.RequestURI]; !ok {
ctx.ResponseWriter.WriteHeader(401)
ctx.WriteString("未登錄")
return
}
}
}
beego.InsertFilter("/v1/*", beego.BeforeRouter, FilterUser)
這里又有一個(gè)大坑乾吻,要自己引入"github.com/astaxie/beego/context"
髓梅,否則IDE會(huì)自動(dòng)引入一個(gè)context,導(dǎo)致代碼報(bào)錯(cuò)绎签,官方文檔上也沒說枯饿,往死里坑人
使用map創(chuàng)建一個(gè)白名單,將兩個(gè)驗(yàn)證碼接口和一個(gè)登錄接口豁免掉
判斷用戶未登錄之后直接return就可以組織后續(xù)的函數(shù)執(zhí)行了