Resty is an HTTP and REST client, and GIN-JWT is a GIN middleware that implements JWT. This article will use both packages to implement a simple user login feature.

Environment to prepare

Before implementing the login function, prepare a service to check whether the user exists. Access service http://127.0.0.1:18081/users? If username=root, information about user root is displayed

{ "total": 1, "data": [ { "id": 1, "username": "root", "password": "CGUx1FN++xS+4wNDFeN6DA==", "nickname": "Super administrator ", "mobile": "13323232323"}]}Copy the code

The result of AES encryption for the password field is displayed. Returns null when the username argument is passed to another string

{
    "total": 0,
    "data": null
}
Copy the code

Now that the preparation is over, let’s look at how to implement the login function.

To achieve certification

First implement a method that invokes the query user service.

func FindUser(userName string) (user sysUser.SysUser, err error) {
	client := resty.New().SetRetryCount(3)
	resp, err := client.R().
		SetQueryParams(map[string]string{
			"username": userName,
		}).
		SetResult(&PagedUser{}).
		Get("http://127.0.0.1:18081/users")
	iferr ! =nil {
		log.Panicln("FindUser err: ", err.Error())
	}
	response := resp.Result().(*PagedUser)
	if response.Total == 1 {
		user = response.Data[0]
		return
	}
	err = errors.New("User does not exist")
	return
}
Copy the code

Here we create a Resty client, set three retries, pass in the username parameter as required by the service, and check whether the user exists by checking the Total value. If the user exists, return the user information, otherwise return an error.

Next we implement the JWT validation section.

var identityKey = "id"

type login struct {
	Username string `form:"username" json:"username" binding:"required"`
	Password string `form:"password" json:"password" binding:"required"`
}

type User struct {
	Id       int
	UserName string
	NickName string
}

func JwtMiddleware(a) (authMiddleware *jwt.GinJWTMiddleware, err error) {
	authMiddleware, err = jwt.New(&jwt.GinJWTMiddleware{
		Realm:       "test zone",
		Key:         []byte("secret key"),
		Timeout:     time.Hour,
		MaxRefresh:  time.Hour,
		IdentityKey: identityKey,
		PayloadFunc: func(data interface{}) jwt.MapClaims {
			if v, ok := data.(*User); ok {
				return jwt.MapClaims{
					identityKey: v.UserName,
				}
			}
			return jwt.MapClaims{}
		},
		IdentityHandler: func(c *gin.Context) interface{} {
			claims := jwt.ExtractClaims(c)
			return &User{
				UserName: claims[identityKey].(string),
			}
		},
		Authenticator: func(c *gin.Context) (interface{}, error) {
			var loginVals login
			iferr := c.ShouldBind(&loginVals); err ! =nil {
				return "", jwt.ErrMissingLoginValues
			}
			userID := loginVals.Username
			password := loginVals.Password

			user, err := http_service.FindUser(userID)
			iferr ! =nil {
				return nil, jwt.ErrFailedAuthentication
			}

			encrypt := utils.PasswordEncrypt(password, userID)
			ifencrypt ! = user.Password.String {return nil, jwt.ErrFailedAuthentication
			}

			return &User{
				Id:       user.Id,
				UserName: user.Username.String,
				NickName: user.Nickname.String,
			}, nil
		},
		Authorizator: func(data interface{}, c *gin.Context) bool {
			if v, ok := data.(*User); ok && v.UserName == "admin" {
				return true
			}

			return false
		},
		Unauthorized: func(c *gin.Context, code int, message string) {
			c.JSON(code, gin.H{
				"code":    code,
				"message": message,
			})
		},
		TokenLookup: "header: Authorization, query: token, cookie: jwt_middleware",
		TokenHeadName: "Bearer",
		TimeFunc: time.Now,
	})
	return
}
Copy the code

The above code is explained in detail in the GIN-based Golang Web Development: Authentication Tool JWT. Let’s focus on the user authentication part: Authenticator.

The method ShouldBind applies model binding to parameters. If you are not familiar with model binding, see the previous article on Golang Web Development based on Gin: Model binding. The FindUser method is then called to check if the user exists, and if so, to verify that the user’s password is correct. All validation goes through the subsequent flow of GIN-JWT by returning to the User structure.

The last step is to add user login routes in Gin.

func main() { r := gin.Default() authMiddleware, err := JwtMiddleware() if err ! = nil { log.Fatal("JWT Error:" + err.Error()) } errInit := authMiddleware.MiddlewareInit() if errInit ! = nil { log.Fatal("authMiddleware.MiddlewareInit() Error:" + errInit.Error()) } r.POST("/login", authMiddleware.LoginHandler) r.Run(":8090") }Copy the code

Now that you’re done, call the /login interface, provide the correct username and password, and you’ll get a successful JSON containing the validated JWT, if anything.

Golang Web Development based on Gin: Implementing user login