1. 输入输出定义
在model/dto/request/user.go
以及model/dto/response/user.go
文件中分别添加以下代码
type UserLoginReq struct {
Name string `json:"name,omitempty" binding:"required"`
Password string `json:"password,omitempty" binding:"required"`
}
type UserLoginSuccessRes struct {
Id uint64 `json:"id"`
Token string `json:"token"`
}
2. 添加控制器处理函数
在api/v1/userController.go
中添加登陆处理函数
// Login POST douyin/v1/user/login/ 用户登陆
func Login(c *gin.Context) {
var userLoginReq request.UserLoginReq
err := c.ShouldBindJSON(&userLoginReq)
if err != nil {
common.FailWithMessage(err.Error(), c)
return
}
usi := service.UserServiceImpl{}
u := usi.GetTableUserByUsername(userLoginReq.Name)
if utils.EnCoder(userLoginReq.Password) == u.Password {
token := utils.GenerateToken(&u)
common.OkWithDetailed(response.UserLoginSuccessRes{Id: uint64(u.ID), Token: token}, "登陆成功", c)
return
} else {
common.FailWithMessage("username or password error", c)
}
}
3. 注册路由
在router/router.go
文件中注册登陆路由
apiRouter.POST("/user/login/", v1.Login)
4. Jwt中间件
用户注册与用户登陆是不需要身份认证的,但是之后的发布视频、评论、关注等功能需要登陆才能操作。需要新增一个身份校验的中间件。先在utils/jwt.go
文件中添加解析token
的函数
var (
TokenExpired = errors.New("token is expired")
TokenNotValidYet = errors.New("token not active yet")
TokenMalformed = errors.New("that's not even a token")
TokenInvalid = errors.New("couldn't handle this token")
)
// ParseToken 从token中解析出StandardClaims
func ParseToken(token string) (*jwt.StandardClaims, error) {
jwtToken, err := jwt.ParseWithClaims(token, &jwt.StandardClaims{}, func(token *jwt.Token) (i interface{}, e error) {
return []byte(global.Config.Jwt.Secret), nil
})
if err != nil {
if ve, ok := err.(*jwt.ValidationError); ok {
if ve.Errors&jwt.ValidationErrorMalformed != 0 {
return nil, TokenMalformed
} else if ve.Errors&jwt.ValidationErrorExpired != 0 {
// Token is expired
return nil, TokenExpired
} else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
return nil, TokenNotValidYet
} else {
return nil, TokenInvalid
}
}
}
if jwtToken != nil {
if claims, ok := jwtToken.Claims.(*jwt.StandardClaims); ok && jwtToken.Valid {
return claims, nil
}
return nil, TokenInvalid
} else {
return nil, TokenInvalid
}
}
在middleware
目录下新建jwt.go
文件
package jwt
import (
"errors"
"faker-douyin/model/common"
"faker-douyin/utils"
"github.com/gin-gonic/gin"
)
func Auth() gin.HandlerFunc {
return func(context *gin.Context) {
auth := context.Request.Header.Get("Authorization")
// 未携带token
if len(auth) == 0 {
common.FailWithMessage("Unauthorized", context)
context.Abort()
return
}
Claims, err := utils.ParseToken(auth)
if err != nil {
// token过期
if errors.Is(utils.TokenExpired, err) {
common.FailWithMessage("token expired", context)
context.Abort()
return
}
// token无效
common.FailWithMessage("Token Error", context)
context.Abort()
return
}
// 解析成功,将userId放入上下文(其实应该将Claims放入上下文,之后Claims会存放更多东西,角色,rbac权限等)
context.Set("userId", Claims.Id)
context.Next()
}
}
5. 测试用户注册
6. 待提高
- 基于
gitflow
的开发:目前都在master
分支上开发,后续会在feature
分支进行开发merge
- 没有单元测试:没有学习好的单元测试