用戶模型已經(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即可。