beego项目实战——注册和登录
上一篇里完成了短信验证码的生成,这一篇里就完成短信验证码的校验,以及后续的登录和注册功能
model
login.go
type Login struct {
Mobile string
Vcode string
}
登录的model,需要手机号和短信验证码
user.go
type User struct {
Id int64
Mobile string `orm:"size(11)"`
Type int `orm:"size(1)"`
}
func init() {
orm.RegisterModel(new(User))
}
// 根据手机号获取或注册用户
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的话写代码会方便很多,性能没达到瓶颈的话orm还是很好用的
Id字段生成数据库时会自动变为主键和自增,不要相信golint的鬼话写成ID
orm.RegisterModel(new(User))
这句放在init函数中用来在一开始注册模型
ReadOrCreate()
尝试从数据库读取,不存在的话就创建一个,这样当用户没有注册的话就相当于直接注册了,该函数返回值分别为是否是新创建的,创建的id,错误
自动生成数据库
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中设计数据库的连接和自动创建表
beego.AppConfig.String
会读取config/app.conf
中的配置文件
orm.RunSyncdb("default", false, true)
设置创建表的规则,三个参数分别为数据库别名,是否先drop再建表,是否打印执行过程
运行的时候就会看到如图所示的建表语句
controller
// @Title Login
// @Description 登录
// @Param body body models.Login true "登录信息"
// @Success 200 {int} 用户id
// @Failure 400 {string} 验证码错误
// @Failure 500 {string} 服务器错误
// @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"] = "验证码错误"
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))
来获取存储在redis中的验证码,此处有坑,redis封装的get取出来是个interface{},需要先转成字节数组,再转成字符串才能用,你说这玩意整的
models.GetUserByMobile
查询用户是否存在,不存在则创建一个
SetSession
用来记录登录态,单机版的直接就用session就好,response里会带着setcookie命令
router
beego.NSNamespace("/login",
beego.NSInclude(
&controllers.LoginController{},
),
),
效果
登录接口验证登录态
还有很重要的一步就是登录了之后要验证登录态,这个涉及的东西就比较复杂了,需要用过滤器来实现
main.go
var FilterUser = func(ctx *context.Context) {
_, ok := ctx.Input.Session("uid").(int)
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)
这里又有一个大坑,要自己引入"github.com/astaxie/beego/context"
,否则IDE会自动引入一个context,导致代码报错,官方文档上也没说,往死里坑人
使用map创建一个白名单,将两个验证码接口和一个登录接口豁免掉
判断用户未登录之后直接return就可以组织后续的函数执行了