We use a series to explain the complete practice of microservices from requirements to online, from code to k8s deployment, from logging to monitoring, etc.
The whole project uses microservices developed by go-zero, which basically includes go-zero and some middleware developed by related go-zero authors. The technology stack used is basically the self-developed components of the go-zero project team, basically go -zero the whole family bucket.
Actual project address: https://github.com/Mikaelemmmm/go-zero-looklook
1. User Center Business Architecture Diagram
2. Dependencies
usercenter-api (user center api) depends on identity-rpc (authorization and authentication rpc), usercenter-rpc (user center rpc)
usercenter-rpc (user center rpc) depends on identity-rpc (authorization center rpc)
Let's look at the project usercenter/cmd/api/desc/usercenter.api, all the external http methods of user api are here
There are 4 business registration, login, obtaining user information, WeChat applet authorization
3. Registration example
1. Register the api service
When we write the api service code, we must first define the method in the service in usercenter.api, and then write the request and response in desc/user. The advantage of this splitting is that it is not so bloated.
a. Define the registration method in usercenter.api as follows
// 用户模块v1版本的接口
@server(
prefix: usercenter/v1
group: user
)
service usercenter {
@doc "注册"
@handler register
post /user/register (RegisterReq) returns (RegisterResp)
.....
}
b. Define RegisterReq\RegisterResp in app/usercenter/cmd/api/desc/user/user.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) Enter the app/usercenter/cmd/api/desc directory from the command line.
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 the app/usercenter/cmd directory)
$ goctl api go -api *.api -dir ../ -style=goZero
d. Open the app/usercenter/cmd/api/internal/logic/user/register.go file
It's very easy here, just call the user's rpc service directly
Here is a little trick. Many students feel that the fields returned by the rpc service are similar to the api definitions, and it is very troublesome to copy them manually every time. Does go have a tool like BeanCopyUtils.copy like java? The answer is definitely yes, you can see the above code copier.Copy, this library is another new work by the author of gorm, are you excited? Then let's continue to see what the rpc that calls the backend looks like.
2. Register rpc service
- Define protobuf file
We create a new usercenter.proto in app/usercenter/cmd/rpc/pb and write the 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);
...
}
- Use goctl to generate code, you don't need to manually type here
1) Enter the app/usercenter/cmd/rpc/pb directory from the command line.
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 the 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 to write logic code
The registration is designed into 2 tables, a user table and a user_auth table. user stores basic user information, and user_auth is related information that can authorize login according to different platforms, so local transactions are designed here, because go-zero transactions need to be in It can only be used in the model, but I have done 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 the transaction to logic
Use directly in logic
Since the project supports applet and mobile phone number, the registration of applet does not require a password, so a process is done when processing the password. The password for the registration of the mobile phone number needs to be passed, and the password for the registration of the applet does not need to be passed. Empty to judge the api service when the mobile phone number is registered
After the usercenter-rpc is successfully registered, you need to request the token to log in to the front end, and directly request the 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{
//生成token,只针对用户服务开放访问
rpc generateToken(GenerateTokenReq) returns(GenerateTokenResp);
.....
}
generatetokenlogic.go
// GenerateToken 生成token,只针对用户服务开放访问.
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)
}
//存入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
}
The registration is successful and go to identity-rpc to get the token, token expiration time, and token replacement time to the api service
Fourth, the business obtains the login user id
When we obtain user information or place an order, we always need to obtain the id of the logged-in user. As we mentioned in the previous article, after we verify the token in the authorized identity service, the parsed userId will be returned to the header. nginx's authReuest
in 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 this userId in the back-end service. For example, we now visit usercenter/v1/user/detail to get the current login user information
ok, you can see that we can get it through ctxdata.GetUidFromCtx(l.ctx), why is it so magical? Let's click on this method
In fact, it is 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 that is userId in the header to access the back-end service, the main function of our back-end service will load a global middleware when it starts, such as main in usercenter-api
app/usercenter/cmd/api/usercenter.go
The global middleware is defined here. As long as there is a request to a certain method of our usercenter-ap, it will enter the global middleware first. The specific content of the middleware is as follows
So do you understand at once, when we request usercenter/v1/user/detail, we will enter this middleware first. In this middleware, we get the parsed userId through X-User in the header of nginx and put it In ctx, when we continue to enter usercenter/v1/user/detail, can we directly take it out through ctx and use it in the business? All the truth is revealed.
The same is true for other user center services to log in, obtain login user information, and authorize log in with a small program. I won't go into too much detail here, just look at the code by yourself.
[Note] The applet is authorized to log in, remember to modify the configuration file, the configuration file here is fake, change it to your own
project address
https://github.com/zeromicro/go-zero
Welcome go-zero
and star support us!
WeChat exchange group
Follow the official account of " Microservice Practice " and click on the exchange group to get the QR code of the community group.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。