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