Microservices have everything from code to k8s deployment series (IV. user center)

We will use a series to explain the complete practice of microservices from requirements to online, from code to k8s deployment, from logging to monitoring.

The whole project uses the micro services developed by go zero, which basically includes go zero and some middleware developed by relevant go zero authors. The technology stack used is basically the self-developed component of the go zero project team, which is basically the go zero software.

Actual project address: https://github.com/Mikaelemmmm/go-zero-looklook

1, User center business architecture

2, Dependency

Usercenter api relies on identity rpc and usercenter rpc

Usercenter rpc depends on identity rpc

Let's look at the project usercenter / CMD / api / desc / usercenter api, all http methods external to the user api are here

There are four business registration, login, obtaining user information and wechat applet authorization

3, Registration example

1. Register api service

When we write api service code, we must first in usercenter Define the methods in the service in the api, and then write request and response in desc/user. The advantage of splitting is that it is not so cumbersome

a. In usercenter The registration methods defined in API are as follows

// Interface of user module v1 version
@server(
	prefix: usercenter/v1
	group: user
)
service usercenter {
  @doc "register"
	@handler register
	post /user/register (RegisterReq) returns (RegisterResp)
  
  .....
}

b. In APP / usercenter / CMD / API / desc / user / user RegisterReq\RegisterResp is defined in the API

type (
	RegisterReq {
		Mobile   string `json:"mobile"`
		Password string `json:"password"`
	}
	RegisterResp {
		AccessToken  string `json:"accessToken"`
		AccessExpire int64  `json:"accessExpire"`
		RefreshAfter int64  `json:"refreshAfter"`
	}
)

c. goctl generates api code

1) From the command line, enter the app/usercenter/cmd/api/desc directory.

2) Go to deploy/script/gencode/gen.sh in the project directory, copy the following command and execute it on the command line (the command line should be switched to app/usercenter/cmd directory)

$ goctl api go -api *.api -dir ../  -style=goZero

d. Open app / usercenter / CMD / API / internal / logic / user / register Go file

It's easy to call user's rpc service directly

Here's a tip. Many students feel that the fields returned by rpc service are similar to the api definition, and it's troublesome to manually copy them every time. Is there any beancopyutils like java in go What about copy? The answer must be yes. You can see the code copier above Copy, this library is another new work by gorm author, isn't it very exciting. Let's continue to see what rpc looks like when calling the backend.

2. Register rpc service

  • Define protobuf file

    We create a new usercenter in app/usercenter/cmd/rpc/pb Proto, write registration method

    //req ,resp
    message RegisterReq {
      string mobile = 1;
      string nickname = 2;
      string password = 3;
      string authKey = 4;
      string authType = 5;
    }
    message RegisterResp {
      string accessToken = 1;
      int64  accessExpire = 2;
      int64  refreshAfter = 3;
    }
    
    //service
    service usercenter {
      rpc register(RegisterReq) returns(RegisterResp);
      ......
    }
    
  • Using goctl to generate code, you don't need to knock it out manually

    1) From the command line, enter the app/usercenter/cmd/rpc/pb directory.

    2) Go to deploy/script/gencode/gen.sh in the project directory, copy the following two commands and execute them on the command line (the command line should be switched to app/usercenter/cmd directory)

    $  goctl rpc protoc *.proto --go_out=../ --go-grpc_out=../  --zrpc_out=../
    $  sed -i "" 's/,omitempty//g' *.pb.go
    
  • Open app / usercenter / CMD / RPC / internal / logic / registerlogic Go write logic code

    Register the design to two tables, one user table and one user table_ Auth table, user is the user that stores basic user information_ Auth is the relevant information that can be authorized to log in according to different platforms, so the local transaction is designed here. Because the transaction of go zero can only be used in the model, but I made a process in the model and exposed it in the model, so it can be used in logic

    The Trans method is defined in the model to expose transactions to logic

    Used directly in logic

    Because the project supports small programs and mobile numbers, and the registration of small programs does not require a password, a process is done when processing the password. The password needs to be passed when registering mobile numbers, and the password does not need to be passed when registering small programs. As for the registration password of mobile numbers, it cannot be empty, and it should be judged by the api service during the registration of mobile numbers

    After the user center RPC is registered successfully, you need to request a token to the front-end login, and directly request identity RPC to issue the user's token

    Identity RPC is as follows

    message GenerateTokenReq {
      int64 userId = 1;
    }
    message GenerateTokenResp {
      string accessToken = 1;
      int64  accessExpire = 2;
      int64  refreshAfter = 3;
    }
    
    
    service identity{
      //Generate a token and only open access to user services
      rpc generateToken(GenerateTokenReq) returns(GenerateTokenResp);
      .....
    }
    

    generatetokenlogic.go

    // GenerateToken generates a token, which is only open to user services
    func (l *GenerateTokenLogic) GenerateToken(in *pb.GenerateTokenReq) (*pb.GenerateTokenResp, error) {
    
    	now := time.Now().Unix()
    	accessExpire := l.svcCtx.Config.JwtAuth.AccessExpire
    	accessToken, err := l.getJwtToken(l.svcCtx.Config.JwtAuth.AccessSecret, now, accessExpire, in.UserId)
    	if err != nil {
    		return nil, errors.Wrapf(ErrGenerateTokenError, "getJwtToken err userId:%d , err:%v", in.UserId, err)
    	}
    
    	//Save to redis
    	userTokenKey := fmt.Sprintf(globalkey.CacheUserTokenKey, in.UserId)
    	err = l.svcCtx.RedisClient.Setex(userTokenKey, accessToken, int(accessExpire))
    	if err != nil {
    		return nil, errors.Wrapf(ErrGenerateTokenError, "SetnxEx err userId:%d, err:%v", in.UserId, err)
    	}
    
    	return &pb.GenerateTokenResp{
    		AccessToken:  accessToken,
    		AccessExpire: now + accessExpire,
    		RefreshAfter: now + accessExpire/2,
    	}, nil
    }
    

    Register successfully and go to identity RPC to get the token, the expiration time of the token and the time of replacing the token to the api service

4, Obtain login user id

When we obtain user information or place an order, we always need to obtain the id of the login user. In the previous article, we said that after verifying the token in the authorization identity service, the parsed userId will be put in the header and returned to authReuest of nginx

In the file app / identity / CMD / API / internal / handler / verify / tokenhandler go

When nginx accesses the back-end service through authRequest, it will pass the header content to the back-end service, because we have configured the following in nginx

In this case, we can get the userId in the back-end service. For example, we can access usercenter/v1/user/detail to get the current login user information

ok, you can see us through ctxdata Getuidfromctx (l.ctx) can be obtained. Why is it so magical? Let's click to see this method

In fact, it's the userId obtained from ctx. Isn't it strange that we clearly put it in the header in nignx? Why can you get it through ctx in the business code of go?

1. [tips] middleware

When nginx carries the x-user ID in the header to access the back-end service, the main function will load a global middleware when our back-end service is started, such as main in the usercenter API

app/usercenter/cmd/api/usercenter.go

The global middleware is defined here. As long as there is a request to a method of usercenter AP, it will enter the global middleware first. The specific contents of the middleware are as follows

So do you understand that when we request usercenter/v1/user/detail, we will first enter the middleware. In this middleware, we get the parsed userId through X-User in the header of nginx and put it into ctx. When we continue to enter usercenter/v1/user/detail, can we directly take it out through ctx and use it in business, The truth came out.

Similarly, other user center service login, access to login user information and applet authorization login are the same reason. There is no longer wordy here. Just look at the code by yourself

[note] when the applet is authorized to log in, remember to modify the configuration file. The configuration file here is false and changed to its own

Project address

https://github.com/zeromicro/go-zero

https://gitee.com/kevwan/go-zero

Welcome to go zero and star support us!

Wechat communication group

Focus on the "micro service practice" official account and click on the exchange group to get the community community's two-dimensional code.

Keywords: Go Mini Program

Added by 1042 on Thu, 10 Feb 2022 07:56:47 +0200