Yalda

哈库呐玛塔塔

嗨,我是张志方,一名 iOS 开发者。


五、登录注册接口开发和JWT

用户模型已经构建完了,可以愉快的写接口开发了,来编写第一个接口,登录/注册接口 首先定义接口routers/routers.go

...
apiv1.POST("auth",v1.AuthStore) //登录/注册接口
...

然后实现接口定义的方法,这时候还只是一个空壳routers/v1/user.go

package v1

import (
    "api/pkg/e"
    "api/pkg/util"
    "github.com/gin-gonic/gin"
)

//登录,注册
func UserStore(c *gin.Context) {
    mobile := c.PostForm("mobile")  //取出请求参数手机号mobile
    vCode := c.PostForm("code") //取出请求参数验证码code

    util.ResponseWithJson(e.SUCCESS,gin.H{
        "Mobile":mobile,
        "Code":vCode,
    },c)
}

有一点需要注意,有些参数是需要做验证的,所以这里使用一个三方验证的依赖
终端执行 go get -u github.com/astaxie/beego/validation 这个是beego框架下的一个表单验证依赖。 根据需求,先根据手机号查询数据库中是否已有这个账号,有的话就返回信息,没有就创建后返回信息。编写这些数据库操作方法models/user.go

...
//根据手机号查找用户
func FindUserByMobile(mobile string) (*User, error) {
    var user User
    err := db.Where("mobile = ?",mobile).First(&user).Error
    return &user,err
}

//创建用户
func CreateUser(mobile string) (*User, error) {
    user := User{
        Mobile: mobile,
    }
    err := db.Create(&user).Error
    return &user, err
}

完善接口方法routers/v1/user.go

package v1

import (
    "api/models"
    "api/pkg/e"
    "api/pkg/util"
    "github.com/astaxie/beego/validation"
    "github.com/gin-gonic/gin"
    "github.com/jinzhu/gorm"
)

//登录,注册接口
func UserStore(c *gin.Context) {
    mobile := c.PostForm("mobile")  //取出请求参数手机号mobile
    vCode := c.PostForm("code") //取出请求参数验证码code

    //对请求对参数进行验证
    validate := validation.Validation{}
    validate.Required(mobile,"Mobile").Message("手机号有误") //因为测试环境,所以使用了Required方法,正式下使用Mobile方法,做手机号校验。
    validate.Length(vCode,4,"Code").Message("验证码格式不正确")
    //校验错误,有错误返回json
    if isOk := checkValidation(&validate, c); isOk == false {   //校验不通过
        return
    }

    //数据库根据手机号查询用户信息
    user,err := models.FindUserByMobile(mobile)
    if gorm.IsRecordNotFoundError(err) {    //如果数据库没有查询到没有用户信息,代表要注册,新创建用户信息
        user,err = models.CreateUser(mobile)
        if err != nil {
            util.ResponseWithJson(e.ERROR, "数据库操作错误", c)
            return
        }
    }else {
        if err !=nil {
            util.ResponseWithJson(e.ERROR, "数据库操作错误", c)
            return
        }
    }

    util.ResponseWithJson(e.SUCCESS,gin.H{
        "User":user,
    },c)
}

/*检查请求参数是否有错误,如果有的话返回false*/
func checkValidation(vali *validation.Validation,c *gin.Context)bool  {
    if vali.HasErrors() {                           //请求的参数有误
        var errs []string                           //创建一个保存错误信息的数组
        for _,err := range vali.Errors{             //遍历错误信息数组,把错误信息添加到数组当中
            errs = append(errs,err.Message)
        }
        util.ResponseWithJson(e.INVALID_PARAMS,errs,c)  //返回客户端错误信息
        return false
    }

    return true
}

重新run一下程序,我们使用postman来分别测试一下无参数情况、只传手机号情况、传完整参数 http://127.0.0.1/api/v1/auth 然后查看数据库查看是否有数据

上述的流程是没有添加短信验证这一环节的,因为手中没有企业账号,所以这一步是省略了的。推荐两个验证码服务平台阿里云短信服务Go文档和MOB免费短信平台 JWT 进行身份校验 终端执行下载JWT go get -u github.com/dgrijalva/jwt-Go 对jwt的使用做封装,pkg/util/jwt.go

package util

import (
    "api/pkg/setting"
    "github.com/dgrijalva/jwt-go"
    "time"
)

var jwtSecret = []byte(setting.AppSetting.JwtSecret)        //jwt密钥

/*在jwt中添加的自定义用户信息,有用户的ID和手机号,也可以加一些其它信息*/
type Claims struct {
    ID uint
    //Mobile string //这里没有使用手机号。因为token字符串可以被解析。。。。
    jwt.StandardClaims
}

/*生成Token*/
func GeterateToken(id uint,mobile string) (string,error) {
    nowTime := time.Now()       //当前时间
    expireTime := nowTime.Add(setting.AppSetting.JwtExpireTime * time.Hour) //过期时间,为了测试这里是3小时后过期

    //设置自定义荷载
    claims := Claims{
        id,
        //mobile,
        jwt.StandardClaims{
            ExpiresAt:expireTime.Unix(),
            Issuer : "blog",
        },
    }

    tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    token, err := tokenClaims.SignedString(jwtSecret)                       //该方法内部生成签名字符串,再用于获取完整、已签名的token

    return token, err
}

/*校验和解析token*/
func ParseToken(token string) (*Claims, error) {
    tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
        return jwtSecret, nil
    })

    if tokenClaims != nil {
        if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
            return claims, nil
        }
    }

    return nil, err
}

在登录/注册接口中, 返给客户端生成的token routers/v1/user.go

...
//登录,注册接口
func UserStore(c *gin.Context) {
...
    //生成token
    token,err := util.GeterateToken(user.ID,user.Mobile)
    if err != nil {
        util.ResponseWithJson(e.ERROR, "创建token失败", c)
        return
    }

    util.ResponseWithJson(e.SUCCESS,gin.H{
        "User":user,
        "Token":token,
    },c)
}
...

这样就返还给客户端token了,客户端获取token后保存,在需要使用token的接口中,在请求header中加入token即可。

最近的文章

六、中间件token鉴权和app升级功能

本篇文章主要为项目添加中间件token的授权、app升级功能。Middleware中间件使用中间件可以对api接口访问前后做处理。例如token校验。接下来使用gin框架的中间件功能。middl...…

继续阅读

更早的文章

四、数据库与构建用户模块

这章开始,我们将会接触到数据库的相关内容,使用了gorm这个库,gorm中文文档这里查看中文文档。进行之前,要保证电脑安装了mysql,可以看我这篇文章安装mysql,安装完成后,要创建数据库和...…

继续阅读
-->