How to use go zero to quickly realize JWT authentication in go

Time:2021-7-27

About what JWT is, you can take a look at the official website. In a word, it is a stateless authentication scheme that can realize server authentication. It is also the most popular cross domain authentication solution at present.

To implement JWT authentication, we need to divide it into the following two steps

  • The client obtains the JWT token.
  • JWT token authentication brought by the server to the client.

1. The client obtains the JWT token

We define a protocol for the client to call and obtain the JWT token. We create a new directory JWT and execute it in the directorygoctl api -o jwt.api, change the generated jwt.api as follows:

type JwtTokenRequest struct {
}

type JwtTokenResponse struct {
  AccessToken  string `json:"access_token"`
  AccessExpire int64  `json:"access_expire"`
  RefreshAfter int64  `json:"refresh_ After ` // it is recommended that the client refresh the absolute time of the token
}

type GetUserRequest struct { 
  UserId string `json:"userId"`
}

type GetUserResponse struct {
  Name string `json:"name"`
}

service jwt-api {
  @handler JwtHandler
  post /user/token(JwtTokenRequest) returns (JwtTokenResponse)
}

@server(
  jwt: JwtAuth
)
service jwt-api {
  @handler JwtHandler
  post /user/info(GetUserRequest) returns (GetUserResponse)
}

Execute in the service JWT Directory:goctl api go -api jwt.api -dir .
Open the jwtlogic.go file and modify itfunc (l *JwtLogic) Jwt(req types.JwtTokenRequest) (*types.JwtTokenResponse, error) {The method is as follows:

func (l *JwtLogic) Jwt(req types.JwtTokenRequest) (*types.JwtTokenResponse, error) {
	var accessExpire = l.svcCtx.Config.JwtAuth.AccessExpire

	now := time.Now().Unix()
	accessToken, err := l.GenToken(now, l.svcCtx.Config.JwtAuth.AccessSecret, nil, accessExpire)
	if err != nil {
		return nil, err
	}

	return &types.JwtTokenResponse{
    AccessToken:  accessToken,
    AccessExpire: now + accessExpire,
    RefreshAfter: now + accessExpire/2,
  }, nil
}

func (l *JwtLogic) GenToken(iat int64, secretKey string, payloads map[string]interface{}, seconds int64) (string, error) {
	claims := make(jwt.MapClaims)
	claims["exp"] = iat + seconds
	claims["iat"] = iat
	for k, v := range payloads {
		claims[k] = v
	}

	token := jwt.New(jwt.SigningMethodHS256)
	token.Claims = claims

	return token.SignedString([]byte(secretKey))
}

Before starting the service, we need to modify the etc / jwt-api.yaml file as follows:

Name: jwt-api
Host: 0.0.0.0
Port: 8888
JwtAuth:
  AccessSecret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  AccessExpire: 604800

Start the server, and then test the token obtained under.

➜ curl --location --request POST '127.0.0.1:8888/user/token'
{"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MDEyNjE0MjksImlhdCI6MTYwMDY1NjYyOX0.6u_hpE_4m5gcI90taJLZtvfekwUmjrbNJ-5saaDGeQc","access_expire":1601261429,"refresh_after":1600959029}

2. The server verifies the JWT token

  1. In the API filejwt: JwtAuthThe marked service indicates that JWT authentication is activated.
  2. You can read the rest / handler / authhandler. Go file for the server JWT implementation.
  3. Modify getuserlogic.go as follows:
func (l *GetUserLogic) GetUser(req types.GetUserRequest) (*types.GetUserResponse, error) {
	return &types.GetUserResponse{Name: "kim"}, nil
}
  • Let’s test the request header without JWT authorization header, and the returned HTTP status code is 401, which is in line with the expectation.
➜ curl -w  "\nhttp: %{http_code} \n" --location --request POST '127.0.0.1:8888/user/info' \
--header 'Content-Type: application/json' \
--data-raw '{
    "userId": "a"
}'

http: 401
  • Add the authorization header request header test.
➜ curl -w  "\nhttp: %{http_code} \n" --location --request POST '127.0.0.1:8888/user/info' \
--header 'Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MDEyNjE0MjksImlhdCI6MTYwMDY1NjYyOX0.6u_hpE_4m5gcI90taJLZtvfekwUmjrbNJ-5saaDGeQc' \
--header 'Content-Type: application/json' \
--data-raw '{
    "userId": "a"
}'
{"name":"kim"}
http: 200

To sum up: the JWT authentication based on go zero is completed. When deploying in the real production environment, accesssecret, accessexpire and refreshafter are configured through the configuration file according to the business scenario. Refreshafter tells the client when it is time to refresh the JWT token. Generally, it is necessary to set a few days before the expiration time.

3. Project address

https://github.com/tal-tech/go-zero

Tal Technology