To ensure the security and stability of the system and protect user data, identity authentication is generally introduced to intercept, verify, and filter user requests. Common identity authentication methods are as follows:

  • JWT: JWT provides a method for issuing Access tokens and verifying the issued signed Access tokens. Tokens themselves contain a set of statements that applications can use to restrict user access to resources.
  • OAuth2: OAuth2 is an authorization framework that provides a detailed set of authorization mechanisms (guidance). Users or applications can authorize third-party applications to access specific resources through public or private Settings.
  • Basic: Use user name and password authentication, carry each request, insecure.

We practice

In this paper, THE JWT authentication mechanism will be introduced into go-Kit micro-service to realize token issuance and verification. The principle of JWT is not explained, you can refer to the references at the end. Simply say the implementation idea:

  • Create a login interface to verify the user name and password. Authentication Generates a token and returns it to the client.
  • Add token authentication to the Calculate interface, encapsulated using middleware provided by Go-Kit.
  • This example uses the go implementation of third-party JWTdgrijalva/jwt-go

Step-1: Code preparation

Copy the directory arithmetic_circuitbreaker_demo, rename it arithmetic_jwt_demo, and rename register to service.

Install dependent JWT third-party libraries:

go get github.com/dgrijalva/jwt-go
Copy the code

Step-2: Create jwt.go

Create the file jwt.go under the service directory.

  • Start by defining the key needed to generate the token (this is the most important thing in JWT and should never be disclosed).
  • Custom declaration. inStandardClaimsOn the basis ofUserId,NameTwo fields, you can extend other fields, such as roles, as needed.
  • definekeyfuncThis method is used as a callback function when validating tokens, as described below.
  • Define the method for generating tokensSign. Here we call JWT third-party library generation directly, and set the token expiration time to 2 minutes for demonstration purposes.

Here is the complete code for jwt.go:

//secret key
var secretKey = []byte("abcd1234! @ # $"// ArithmeticCustomClaims Custom declarationtype ArithmeticCustomClaims struct {
	UserId string `json:"userId"`
	Name   string `json:"name"Jwt.standardclaims} // jwtKeyFunc jwtKeyFunc(token * jwt.token) (interface{}, error) {returnSecretKey, nil} // Sign generates token func Sign(name, uid string) (string, error) { ExpAt := time.now ().add (time.duration (2) * time.minute).unix () // Create declaration claims := ArithmeticCustomClaims{ UserId: uid, Name: name, StandardClaims: jwt.StandardClaims{ ExpiresAt: expAt, Issuer:"system",},} // Create a token and specify an encryption algorithm as HS256 token := jwt.NewWithClaims(jwt.SigningMethodHS256, Claims) // Generate a tokenreturn token.SignedString(secretKey)
}
Copy the code

Step-3: adds a login interface

Service layer: Add login interfaces, in order of go-kit architecture:

  • Add the Login method to the Service interface.
  • Implement the Login method in ArithmeticService: validate the user name and password and generate the token by calling JWT’s Sign method;
  • Implement the Login method in loggingMiddleware;
  • Implement the Login method in metricMiddleware;
// Service Define a service interface
typeService interface {/ /... // HealthCheck Login(name,pwd string) (string, error)
}

func (s ArithmeticService) Login(name, pwd string) (string, error) {
	if name == "name" && pwd= ="pwd" {
		token, err := Sign(name, pwd)
		return token, err
	}

	return "", errors.New("Your name or password dismatch")}Copy the code

Endpoint layer: Add the request and response entity structure required by the login interface, and write the method to create an Endpoint.

// AuthRequest
type AuthRequest struct {
	Name string `json:"name"`
	Pwd  string `json:"pwd"`
}

// AuthResponse
type AuthResponse struct {
	Success bool   `json:"success"`
	Token   string `json:"token"`
	Error   string `json:"error"`
}

func MakeAuthEndpoint(svc Service) endpoint.Endpoint {
	return func(ctx context.Context, request interface{}) (response interface{}, err error) {
		req := request.(AuthRequest)

		token, err := svc.Login(req.Name, req.Pwd)

		var resp AuthResponse
		iferr ! = nil { resp = AuthResponse{ Success: err == nil, Token: token, Error: err.Error(), } }else {
			resp = AuthResponse{
				Success: err == nil,
				Token:   token,
			}
		}

		return resp, nil
	}
}
Copy the code

Transport layer: compile decode and encode methods, add login interface routing. At the same time, token checking logic is added to the Calculate interface: Authentication information is read from the HTTP request header before the request is processed, and the request context is added if the read is successful. This uses the HTTPToContext method provided by Go-Kit directly.

func decodeLoginRequest(_ context.Context, r *http.Request) (interface{}, error) {
	var loginRequest AuthRequest
	iferr := json.NewDecoder(r.Body).Decode(&loginRequest); err ! = nil {return nil, err
	}
	return loginRequest, nil
}

func encodeLoginResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
	w.Header().Set("Content-Type"."application/json; charset=utf-8")
	return json.NewEncoder(w).Encode(response)
}
Copy the code

Adding HTTP routes:

r.Methods("POST").Path("/calculate/{type}/{a}/{b}").Handler(kithttp.NewServer( endpoints.ArithmeticEndpoint, decodeArithmeticRequest, encodeArithmeticResponse, // Added options append(options, kithttp.serverbefore (kitjwt.httptoContext ()))... ,)) / /... r.Methods("POST").Path("/login").Handler(kithttp.NewServer( endpoints.AuthEndpoint, decodeLoginRequest, encodeLoginResponse, options... )),Copy the code

Step-4: Modify main.go

Extend the original ArithmeticEndpoints and add AuthEndpoint. Add AuthEndpoint creation logic code, add traffic limiting, link tracing and other packaging for it.

AuthEndpoint := MakeAuthEndpoint(SVC) authEndpoint = NewTokenBucketLimitterWithBuildIn(ratebucket)(authEndpoint) authEndpoint = kitzipkin.TraceEndpoint(zipkinTracer,"login-endpoint"// Encapsulate the arithmeticmeticendPoints health check and login Endpoint to arithmeticmeticendpoints endpts := ArithmeticEndpoints{arithmeticmeticendpoint:  calEndpoint, HealthCheckEndpoint: healthEndpoint, AuthEndpoint: authEndpoint, }Copy the code

Since we require the Calculate interface to be accessible only if the token is valid, add the token verification code to calEndpoint (the last line of code, directly using the middleware provided by Go-Kit) :

calEndpoint := MakeArithmeticEndpoint(svc)
calEndpoint = NewTokenBucketLimitterWithBuildIn(ratebucket)(calEndpoint)
calEndpoint = kitzipkin.TraceEndpoint(zipkinTracer, "calculate-endpoint")(calEndpoint)
calEndpoint = kitjwt.NewParser(jwtKeyFunc, jwt.SigningMethodHS256, kitjwt.StandardClaimsFactory)(calEndpoint)
Copy the code

Step-5: Run & tests

Enable Consul, Zipkin, and Hystrix-Dashboard via Docker-compose; Then start gateyway (specify Consul address); Finally, start service (specifying consul and service address).

Set in the Postman POST request http://localhost:9090/arithmetic/login, Body for the following contents:

{
    "name": "name"."pwd": "pwd"
}
Copy the code

You can see the following results:

Then, request the Calculate interface and set Authorization in the Header, resulting in the following:

Two minutes later, you test again and find that the returned token has expired.

conclusion

In this paper, JWT is introduced into go-Kit microservice based on examples. The Login interface was added to make the Calculate interface work only if the token is valid. Due to the authentication characteristics of JWT, the validity of the token requested by the user after successful login is no longer dependent on the authentication center. Compared with OAuth2, it can greatly reduce the pressure of the authentication center and make the horizontal expansion of micro-services easier.

reference

  • This article sample code @github
  • JSON Web Token Tutorial
  • JWT official website
  • Dgrijalva/Jwt-go (a GO implementation of JWT)

This article is first published in my wechat public account [Xi Yi Ang bar], welcome to scan code attention!