Go實(shí)戰(zhàn)項(xiàng)目【五】登錄注冊接口開發(fā)和JWT

用戶模型已經(jīng)構(gòu)建完了,可以愉快的寫接口開發(fā)了,來編寫第一個(gè)接口,登錄/注冊接口

首先定義接口
routers/routers.go

...
apiv1.POST("auth",v1.AuthStore) //登錄/注冊接口
...

然后實(shí)現(xiàn)接口定義的方法,這時(shí)候還只是一個(gè)空殼
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")  //取出請求參數(shù)手機(jī)號mobile
    vCode := c.PostForm("code") //取出請求參數(shù)驗(yàn)證碼code

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

有一點(diǎn)需要注意,有些參數(shù)是需要做驗(yàn)證的,所以這里使用一個(gè)三方驗(yàn)證的依賴
終端執(zhí)行

go get -u github.com/astaxie/beego/validation

這個(gè)是beego框架下的一個(gè)表單驗(yàn)證依賴。

根據(jù)需求,先根據(jù)手機(jī)號查詢數(shù)據(jù)庫中是否已有這個(gè)賬號,有的話就返回信息,沒有就創(chuàng)建后返回信息。編寫這些數(shù)據(jù)庫操作方法
models/user.go

...
//根據(jù)手機(jī)號查找用戶
func FindUserByMobile(mobile string) (*User, error) {
    var user User
    err := db.Where("mobile = ?",mobile).First(&user).Error
    return &user,err
}

//創(chuàng)建用戶
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")  //取出請求參數(shù)手機(jī)號mobile
    vCode := c.PostForm("code") //取出請求參數(shù)驗(yàn)證碼code

    //對請求對參數(shù)進(jìn)行驗(yàn)證
    validate := validation.Validation{}
    validate.Required(mobile,"Mobile").Message("手機(jī)號有誤") //因?yàn)闇y試環(huán)境,所以使用了Required方法,正式下使用Mobile方法,做手機(jī)號校驗(yàn)。
    validate.Length(vCode,4,"Code").Message("驗(yàn)證碼格式不正確")
    //校驗(yàn)錯(cuò)誤,有錯(cuò)誤返回json
    if isOk := checkValidation(&validate, c); isOk == false {   //校驗(yàn)不通過
        return
    }

    //數(shù)據(jù)庫根據(jù)手機(jī)號查詢用戶信息
    user,err := models.FindUserByMobile(mobile)
    if gorm.IsRecordNotFoundError(err) {    //如果數(shù)據(jù)庫沒有查詢到?jīng)]有用戶信息,代表要注冊,新創(chuàng)建用戶信息
        user,err = models.CreateUser(mobile)
        if err != nil {
            util.ResponseWithJson(e.ERROR, "數(shù)據(jù)庫操作錯(cuò)誤", c)
            return
        }
    }else {
        if err !=nil {
            util.ResponseWithJson(e.ERROR, "數(shù)據(jù)庫操作錯(cuò)誤", c)
            return
        }
    }

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

/*檢查請求參數(shù)是否有錯(cuò)誤,如果有的話返回false*/
func checkValidation(vali *validation.Validation,c *gin.Context)bool  {
    if vali.HasErrors() {                           //請求的參數(shù)有誤
        var errs []string                           //創(chuàng)建一個(gè)保存錯(cuò)誤信息的數(shù)組
        for _,err := range vali.Errors{             //遍歷錯(cuò)誤信息數(shù)組,把錯(cuò)誤信息添加到數(shù)組當(dāng)中
            errs = append(errs,err.Message)
        }
        util.ResponseWithJson(e.INVALID_PARAMS,errs,c)  //返回客戶端錯(cuò)誤信息
        return false
    }

    return true
}

重新run一下程序,我們使用postman來測試一下
無參數(shù)情況


無參數(shù)

只傳手機(jī)號情況


傳手機(jī)號參數(shù)

傳完整參數(shù)


完整參數(shù)

查看數(shù)據(jù)庫


數(shù)據(jù)庫

可以看到是成功了的。

上述的流程是沒有添加短信驗(yàn)證這一環(huán)節(jié)的,因?yàn)槭种袥]有企業(yè)賬號,所以這一步是省略了的。推薦兩個(gè)驗(yàn)證碼服務(wù)平臺阿里云短信服務(wù)Go文檔MOB免費(fèi)短信平臺

JWT 進(jìn)行身份校驗(yàn)

終端執(zhí)行下載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和手機(jī)號,也可以加一些其它信息*/
type Claims struct {
    ID uint
    //Mobile string //這里沒有使用手機(jī)號。因?yàn)閠oken字符串可以被解析。。。。
    jwt.StandardClaims
}

/*生成Token*/
func GeterateToken(id uint,mobile string) (string,error) {
    nowTime := time.Now()       //當(dāng)前時(shí)間
    expireTime := nowTime.Add(setting.AppSetting.JwtExpireTime * time.Hour) //過期時(shí)間,為了測試這里是3小時(shí)后過期

    //設(shè)置自定義荷載
    claims := Claims{
        id,
        //mobile,
        jwt.StandardClaims{
            ExpiresAt:expireTime.Unix(),
            Issuer : "blog",
        },
    }

    tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    token, err := tokenClaims.SignedString(jwtSecret)                       //該方法內(nèi)部生成簽名字符串,再用于獲取完整、已簽名的token

    return token, err
}

/*校驗(yàn)和解析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, "創(chuàng)建token失敗", c)
        return
    }

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

這樣就返還給客戶端token了,客戶端獲取token后保存,在需要使用token的接口中,在請求header中加入token即可。

點(diǎn)關(guān)注,不迷路

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容