在Golang语言中, jwt-go 库提供了一些jwt编码和验证的工具,因此我们很容易使用该库来实现token认证。
另外,我们也知道 gin 框架中支援使用者自定义middleware,我们可以很好的将jwt相关的逻辑封装在middleware中,然後对具体的介面进行认证。
go get -u github.com/dgrijalva/jwt-go
又可将其称作Payload,以Json的形式将使用者相关讯息,甚至是过期时间、签证发放时间都写在这
app/middleware/jwt-token.go
// MyClaims Customer jwt.StandardClaims
type MyClaims struct {
Account string `json:"account"`
jwt.StandardClaims
}
MyClaims
,并除了jwt-go
原本的jwt.StandardClaims
外,我们还另外储存了Account的资讯再来我们会写个产生Token的Function,用以产生用来认证的JWT Token。
app/middleware/jwt-token.go
// GenToken Create a new token
func GenToken(account string) (string, error) {
c := MyClaims{
account,
jwt.StandardClaims{
ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(),
Issuer: "Flynn",
},
}
// Choose specific algorithm
token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
// Choose specific Signature
return token.SignedString(SecretKey)
}
接下来则是写个Login function来让Login API的Router做使用
app/controller/user.go
// AuthHandler @Summary
// @Tags user
// @version 1.0
// @produce application/json
// @param register body Login true "login"
// @Success 200 string successful return token
// @Router /v1/users/login [post]
func (u UsersController) AuthHandler(c *gin.Context) {
var form Login
bindErr := c.BindJSON(&form)
if bindErr != nil {
c.JSON(http.StatusOK, gin.H{
"code": -1,
"msg": "Invalid params",
})
return
}
userOne, err := service.LoginOneUser(form.Account, form.Password)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"status": -1,
"msg": "Failed to parse params" + err.Error(),
"data": nil,
})
}
if userOne == nil {
c.JSON(http.StatusNotFound, gin.H{
"status": -1,
"msg": "User not found",
"data": nil,
})
}
if userOne != nil {
tokenString, _ := middleware.GenToken(form.Account)
c.JSON(http.StatusOK, gin.H{
"code": 0,
"msg": "Success",
"data": gin.H{"token": tokenString},
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"msg": "Verified Failed.",
})
return
}
再来则是写一个验证JWT Token的Middleware来给router使用
app/midddleware/jwt-token.go
// ParseToken Parse token
func ParseToken(tokenString string) (*MyClaims, error) {
token, err := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (i interface{}, err error) {
return SecretKey, nil
})
if err != nil {
return nil, err
}
// Valid token
if claims, ok := token.Claims.(*MyClaims); ok && token.Valid {
return claims, nil
}
return nil, errors.New("invalid token")
}
// JWTAuthMiddleware Middleware of JWT
func JWTAuthMiddleware() func(c *gin.Context) {
return func(c *gin.Context) {
// Get token from Header.Authorization field.
authHeader := c.Request.Header.Get("Authorization")
if authHeader == "" {
c.JSON(http.StatusUnauthorized, gin.H{
"code": -1,
"msg": "Authorization is null in Header",
})
c.Abort()
return
}
parts := strings.SplitN(authHeader, " ", 2)
if !(len(parts) == 2 && parts[0] == "Bearer") {
c.JSON(http.StatusUnauthorized, gin.H{
"code": -1,
"msg": "Format of Authorization is wrong",
})
c.Abort()
return
}
// parts[0] is Bearer, parts is token.
mc, err := ParseToken(parts[1])
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{
"code": -1,
"msg": "Invalid Token.",
})
c.Abort()
return
}
// Store Account info into Context
c.Set("account", mc.Account)
// After that, we can get Account info from c.Get("account")
c.Next()
}
}
gin.Context
的Header拿出Authorization token,接着就是对该Token进行验证,并将验证失败的地方补上Response。app/config/route.go
posts.GET("/:id", middleware.JWTAuthMiddleware(), controller.QueryUsersController().GetUser)
JWTAuthMiddleware()
main.go
// @title Gin swagger
// @version 1.0
// @description Gin swagger
// @contact.name Flynn Sun
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @host localhost:8080
// schemes http
// @securityDefinitions.apikey BearerAuth
// @in header
// @name Authorization
func main() {
BearerAuth
,产生新的swag template,这样Swagger页面才有地方让人输入Tokenapp/controller/user.go
// GetUser @Summary
// @Tags user
// @version 1.0
// @produce application/json
// @Security BearerAuth
// @param id path int true "id" default(1)
// @Success 200 string successful return data
// @Router /v1/users/{id} [get]
func (u UsersController) GetUser(c *gin.Context) {
@Security BearerAuth
这行annotation,否则他会吃不到swagger的BearerAuth token最後则记得在专案根目录输入swag init
来重新产生swagger template,否则上面更改的swagger shit不会生效喔。
首先我们Login并取得有效token
再来,假设没有输入token就执行需要JWT验证的API,就会获得以下回应
因此我们需要到swagger页面上方找到 Authorization Button,并输入我们的token:
Bearer <token>
接着就可以再次地去执行需要JWT验证的API了
这章节我们透过实战来将jwt-go
与现有的後端程序码进行结构,从middleware、router、controller再到swagger都实装了一遍,如果有细节不懂者可以参考下方连结,这次的code我也会放在这。
https://github.com/Neskem/Ironman-2021/tree/Day-21
>>: Unity与Photon的新手相遇旅途 | Day21-Photon Lobby UI (上)
Python - PySparkPracticeQuestions - PySpark 练习题参考笔...
Coroutine 是非同步程序的解决方案,我们将耗时的任务置放在 suspend 函式中,在正常的...
时间回到刚毕业时的我,对於未来想从事的工作主要从过去的实习经验以及本身觉得有兴趣的领域寻找,而在系列...
今天我们继续介绍一些比较知名的AI作曲的公司/软件。 Jukedeck Jukedeck可以说是AI...