The article was first published on my blog ISLAND and my wechat official account
In projects with separate front and back ends, more and more projects use JWT instead of traditional cookies. Here we use JWT in combination with Gin as a login authorization and permission verification.
🔑 What is JWT
The full name of JWT is JSON WEB TOKEN, which is widely used in front-end and back-end systems.
JWT constitute
JWT is made up of three sections. HEADER, PAYLOAD, VERIFY SIGNATURE. Segmentation.
HEADER
Header is made up of a TYP and AN ALG, tyP being specified as JWT, and ALG being the encryption algorithm used.
{
"alg": "HS256"."typ": "JWT"
}
Copy the code
PAYLOAD
Payload is the carrier of the JWT, the information that we’re carrying. So this is a piece of information that we can customize, we can define what information we want to store, what fields. This part of the information should not be too much, it will affect the size of JWT generation, and do not store sensitive data in this part, the front-end of the data can parse and obtain the information inside the token.
The official has given us seven default fields, we can not use all of them, or we can add the fields we need.
The name of the | meaning |
---|---|
Audience | Represents the JWT audience |
ExpiresAt | The failure time |
Id | Issue number |
IssuedAt | The issuance of time |
Issuer | Issued by people |
NotBefore | Effect of time |
Subject | The theme |
VERIFY SIGNATURE
This is also the last section of the JWT, which is computed by an algorithm.
The header is base64Url encoded, and the payload is base64Url encoded. After the encoding is complete, the. Let’s connect them.
base64UrlEncode(header).base64UrlEncode(payload)
Copy the code
Once I’ve done that, I need to encrypt the top part using the encryption algorithm specified in our header, and we also need to insert one of our keys to make sure my JWT issue is secure.
That’s part three.
When all three parts are completed, the JWT as shown in the figure above is generated by dividing the three parts using.
JWT login principle
Simply put, when the user logs in, the server verifies whether the login name and password are correct. If correct, JWT will be generated and returned to the client. Each subsequent request will say that JWT is carried in the head. Each time, the server will obtain whether the JWT of the head is correct. If it is correct, the request will be executed correctly.
Generate JWT 🔒 Gin
There are many JWT libraries for the GO language. Jwt. IO also gives a lot. Jwt-go is used here
"github.com/dgrijalva/jwt-go"
We revamped the login method.
// omit the code
expiresTime := time.Now().Unix() + int64(config.OneDayOfHours)
claims := jwt.StandardClaims{
Audience: user.Username, / / audience
ExpiresAt: expiresTime, // Expiration time
Id: string(user.ID), / / number
IssuedAt: time.Now().Unix(), // Issue time
Issuer: "gin hello"./ / issue
NotBefore: time.Now().Unix(), // Effective time
Subject: "login"./ / theme
}
var jwtSecret = []byte(config.Secret)
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// omit the code
Copy the code
Here, config.OneDayOfHours sets the expiration time, here it’s a day. StandardClaims generates the standard carrier, the seven fields mentioned above, where the number is set to the user id. Where jwtSecret is the key we set up,
So we’re using the HS256 algorithm to generate tokenClaims, so that’s our HEADER part and PAYLOAD.
token, err := tokenClaims.SignedString(jwtSecret)
Copy the code
This generates our token. We want to concatenate our token and Bearer with a space between them.
token = "Bearer "+ token
Copy the code
Generation of Bearer tokens.
JWT is generated from this section when our user logs in.
Here is the complete code:
func CreateJwt(ctx *gin.Context) {
// Get the user
user := &model.User{}
result := &model.Result{
Code: 200,
Message: "Login successful",
Data: nil,}ife := ctx.BindJSON(&user); e ! =nil {
result.Message = "Data binding failed"
result.Code = http.StatusUnauthorized
ctx.JSON(http.StatusUnauthorized, gin.H{
"result": result,
})
}
u := user.QueryByUsername()
if u.Password == user.Password {
expiresTime := time.Now().Unix() + int64(config.OneDayOfHours)
claims := jwt.StandardClaims{
Audience: user.Username, / / audience
ExpiresAt: expiresTime, // Expiration time
Id: string(user.ID), / / number
IssuedAt: time.Now().Unix(), // Issue time
Issuer: "gin hello"./ / issue
NotBefore: time.Now().Unix(), // Effective time
Subject: "login"./ / theme
}
var jwtSecret = []byte(config.Secret)
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
if token, err := tokenClaims.SignedString(jwtSecret); err == nil {
result.Message = "Login successful"
result.Data = "Bearer " + token
result.Code = http.StatusOK
ctx.JSON(result.Code, gin.H{
"result": result,
})
} else {
result.Message = "Login failed"
result.Code = http.StatusOK
ctx.JSON(result.Code, gin.H{
"result": result,
})
}
} else {
result.Message = "Login failed"
result.Code = http.StatusOK
ctx.JSON(result.Code, gin.H{
"result": result,
})
}
}
Copy the code
Through the.http request test, the results are as follows
{
"result": {
"code": 200."message": "Login successful"."data": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiIxMjMiLCJleHAiOjE1NjQ3OTY0MzksImp0aSI6Ilx1MDAwMCIsImlhdCI6MTU2NDc5NjQxOSw iaXNzIjoiZ2luIGhlbGxvIiwibmJmIjoxNTY0Nzk2NDE5LCJzdWIiOiJsb2dpbiJ9.CpacmfBSMgmK2TgrT-KwNB60bsvwgyryGQ0pWZr8laU"}}Copy the code
This completes the token generation.
🔐 Gin validation Token
Then, the next step is to complete the token verification.
Remember how we verified user authorization earlier? Yes, check the user cookies in the middleware. In the same way, we check whether the user JWT is valid.
Write our middleware.
New middleware/Auth. Go
First, we’ll write our method for parsing tokens, parseToken().
func parseToken(token string) (*jwt.StandardClaims, error) {
jwtToken, err := jwt.ParseWithClaims(token, &jwt.StandardClaims{}, func(token *jwt.Token) (i interface{}, e error) {
return []byte(config.Secret), nil
})
if err == nil&& jwtToken ! =nil {
if claim, ok := jwtToken.Claims.(*jwt.StandardClaims); ok && jwtToken.Valid {
return claim, nil}}return nil, err
}
Copy the code
The token is resolved by passing in our token.
Complete middleware code
func Auth(a) gin.HandlerFunc {
return func(context *gin.Context) {
result := model.Result{
Code: http.StatusUnauthorized,
Message: "Unable to authenticate, log in again",
Data: nil,
}
auth := context.Request.Header.Get("Authorization")
if len(auth) == 0 {
context.Abort()
context.JSON(http.StatusUnauthorized, gin.H{
"result": result,
})
}
auth = strings.Fields(auth)[1]
/ / validation token
_, err := parseToken(auth)
iferr ! =nil {
context.Abort()
result.Message = "The token expired" + err.Error()
context.JSON(http.StatusUnauthorized, gin.H{
"result": result,
})
} else {
println("Token right")
}
context.Next()
}
}
Copy the code
Firstly, the tokens were obtained in the request header, then the tokens were analyzed, Bearer and JWT were split out, and JWT was verified.
We only need to add middleware verification to the routes we need to verify.
router.GET("/", middleware.Auth(), func(context *gin.Context) {
context.JSON(http.StatusOK, time.Now().Unix())
})
Copy the code
We need to carry tokens when we access /
GET http://localhost:8080 Content-Type: application/json Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiIxMjMiLCJleHAiOjE1NjQ3OTQzNjIsImp0aSI6Ilx1MDAwMCIsImlhdCI6MTU2NDc5NDM0Miw iaXNzIjoiZ2luIGhlbGxvIiwibmJmIjoxNTY0Nzk0MzQyLCJzdWIiOiJsb2dpbiJ9.uQxGMsftyVFtYIGwQVm1QB2djw-uMfDbw81E5LMjliUCopy the code
✍ summary
This section describes what JWT is and how to use it in Gin. However, do not be too superstitious about JWT. There are many problems with JWT. For example, JWT failure can only be caused by time expiration. Choose the right technology in the right place to maximize the advantage.
👨💻 Code of this section
Github
Article history
Gin(I):Hello Gin(II): Routing Router Gin(III): Template TMPL Gin(IV): Form submission checksum model binding Gin(V): Connection to MySQL Gin(VI): File upload Gin(VII): Use and definition of middleware Gin(eight): use of cookies Gin(nine): Generate restful interface Gin(ten): Integrate Swagger Gin(eleven) Integrate ORM-GORM Gin(twelve) integrate JWT