我们用一个系列来讲解从需求到上线、从代码到k8s部署、从日志到监控等各个方面的微服务完整实践。

整个项目使用了go-zero开发的微服务,基本包含了go-zero以及相关go-zero作者开发的一些中间件,所用到的技术栈基本是go-zero项目组的自研组件,基本是go-zero全家桶了。

实战项目地址:https://github.com/Mikaelemmmm/go-zero-looklook

一、用户中心业务架构图

二、依赖关系

usercenter-api(用户中心api) 依赖 identity-rpc(授权认证rpc)、usercenter-rpc(用户中心rpc)

usercenter-rpc(用户中心rpc)依赖 identity-rpc(授权中心rpc)

我们看项目usercenter/cmd/api/desc/usercenter.api ,所有的用户api对外的http方法都在这里面

这里面有4个业务注册、登陆、获取用户信息、微信小程序授权

三、注册举例

1、注册api服务

我们在写api服务代码的时候是先要在usercenter.api中定义好service中的方法,然后在desc/user中写request、response,这样拆分开的好处是不那么臃肿

a、在usercenter.api中定义注册方法如下

// 用户模块v1版本的接口
@server(
prefix: usercenter/v1
group: user
)
service usercenter {
@doc "注册"
@handler register
post /user/register (RegisterReq) returns (RegisterResp) .....
}

b、在app/usercenter/cmd/api/desc/user/user.api中定义RegisterReq\RegisterResp

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生成api代码

1)命令行进入app/usercenter/cmd/api/desc目录下。

2)去项目目录下deploy/script/gencode/gen.sh中,复制如下一条命令,在命令行中执行(命令行要切换到app/usercenter/cmd目录)

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

d、打开app/usercenter/cmd/api/internal/logic/user/register.go文件

这里就很容易了,直接调用user的rpc服务即可

这里有个小技巧,很多同学感觉rpc服务返回的字段跟api定义差不多,每次都要手动去复制很麻烦,那么go有没有像java一样的BeanCopyUtils.copy 这种工具呢?答案肯定是有的,可以看上面的代码copier.Copy ,这个库是gorm作者的另一款新作,是不是很兴奋。 那我们继续看看调用后端的rpc是什么样子的。

2、注册rpc服务

  • 定义protobuf文件

    我们在app/usercenter/cmd/rpc/pb中新建usercenter.proto,写入注册方法

    //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);
    ......
    }
  • 使用goctl生成代码,这里不需要自己手动敲

    1)命令行进入app/usercenter/cmd/rpc/pb目录下。

    2)去项目目录下deploy/script/gencode/gen.sh中,复制如下两条命令,在命令行中执行(命令行要切换到app/usercenter/cmd目录)

    $  goctl rpc protoc *.proto --go_out=../ --go-grpc_out=../  --zrpc_out=../
    $ sed -i "" 's/,omitempty//g' *.pb.go
  • 打开app/usercenter/cmd/rpc/internal/logic/registerLogic.go写逻辑代码

    注册设计到2张表,一个user表,一个user_auth表,user是存储用户基本信息的,user_auth是可以根据不同平台授权登陆的相关信息,所以这里设计到本地事务,由于go-zero的事务要在model中才能使用,但是我在model中做了个处理,把它在model中暴露出来,就可以在logic中使用

    model中定义了Trans方法暴露事务给logic

    在logic中直接使用

    由于项目支持小程序、手机号,小程序注册不需要密码,所以在处理密码时候做了个处理,手机号注册就要传递密码,小程序注册就不需要传递密码,至于手机号注册密码不能为空要在手机号注册时候的api服务自己判断

    在usercenter-rpc注册成功之后,需要请求token给前端登陆,直接请求identity-rpc颁发该用户的token

    identity-rpc中如下

    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
    }

    注册成功并去identity-rpc拿到token、token过期时间、置换token的时间给api服务

四、业务获取登陆用户id

当我们在获取用户信息,或者下单等场景下总要获取登陆用户的id,前一篇我们讲到,我们在授权identity服务中校验完token,解析出来的userId会放到header中返回给nginx的authReuest

在文件app/identity/cmd/api/internal/handler/verify/tokenHandler.go

nginx通过authRequest然后访问后端的服务时候,会把header内容传递给后端服务,因为我们在nginx中配置了如下

那这样的话,我们在后端服务就可以拿到这个userId了,比如我们现在访问usercenter/v1/user/detail获取当前登陆用户信息

ok,可以看到我们通过 ctxdata.GetUidFromCtx(l.ctx)就可以拿到,为什么这么神奇呢?我们点开看看这个方法

实际上就是从ctx中拿到的userId,是不是很奇怪,我们明明在nignx就放在了header中,你在go的业务代码中为什么能通过ctx拿到?

1、【小技巧】middleware

当nginx在header中携带了x-user就是userId来访问后端服务的时候,我们后端服务在启动时main函数会加载一个全局中间件,比如usercenter-api中的main

app/usercenter/cmd/api/usercenter.go

这里定义了全局中间件,只要有请求到我们usercenter-ap某个方法之前,都会先进入全局中间件中,中间件具体内容如下

所以是不是一下就明白了,在请求我们usercenter/v1/user/detail时候,会先进入这个中间件,在这个中间件内,我们通过nginx的header中的X-User拿到解析后的userId放到ctx中,那继续进入到usercenter/v1/user/detail时候,我们是不是就可以通过ctx直接取出来在业务中用啦,一切真相大白。

同样其他用户中心服务登陆、获取登陆用户信息、小程序授权登陆都是一个道理,这里就不再啰嗦了,自行看代码即可

【注】小程序授权登陆,记得修改配置文件,这里的配置文件是假的,改成自己的

项目地址

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

欢迎使用 go-zerostar 支持我们!

微信交流群

关注『微服务实践』公众号并点击 交流群 获取社区群二维码。

微服务从代码到k8s部署应有尽有系列(四、用户中心)的更多相关文章

  1. 微服务从代码到k8s部署应有尽有系列(一)

    从本篇文章开始,我们用一个系列来讲解从需求到上线.从代码到k8s部署.从日志到监控等各个方面的微服务完整实践. 实战项目地址:https://github.com/Mikaelemmmm/go-zer ...

  2. 微服务从代码到k8s部署应有尽有系列(二、网关)

    我们用一个系列来讲解从需求到上线.从代码到k8s部署.从日志到监控等各个方面的微服务完整实践. 整个项目使用了go-zero开发的微服务,基本包含了go-zero以及相关go-zero作者开发的一些中 ...

  3. 微服务从代码到k8s部署应有尽有系列(三、鉴权)

    我们用一个系列来讲解从需求到上线.从代码到k8s部署.从日志到监控等各个方面的微服务完整实践. 整个项目使用了go-zero开发的微服务,基本包含了go-zero以及相关go-zero作者开发的一些中 ...

  4. 微服务从代码到k8s部署应有尽有系列(五、民宿服务)

    我们用一个系列来讲解从需求到上线.从代码到k8s部署.从日志到监控等各个方面的微服务完整实践. 整个项目使用了go-zero开发的微服务,基本包含了go-zero以及相关go-zero作者开发的一些中 ...

  5. 微服务从代码到k8s部署应有尽有系列(六、订单服务)

    我们用一个系列来讲解从需求到上线.从代码到k8s部署.从日志到监控等各个方面的微服务完整实践. 整个项目使用了go-zero开发的微服务,基本包含了go-zero以及相关go-zero作者开发的一些中 ...

  6. 微服务从代码到k8s部署应有尽有系列(十四、部署环境搭建)

    我们用一个系列来讲解从需求到上线.从代码到k8s部署.从日志到监控等各个方面的微服务完整实践. 整个项目使用了go-zero开发的微服务,基本包含了go-zero以及相关go-zero作者开发的一些中 ...

  7. 微服务从代码到k8s部署应有尽有系列(七、支付服务)

    我们用一个系列来讲解从需求到上线.从代码到k8s部署.从日志到监控等各个方面的微服务完整实践. 整个项目使用了go-zero开发的微服务,基本包含了go-zero以及相关go-zero作者开发的一些中 ...

  8. 微服务从代码到k8s部署应有尽有系列(八、各种队列)

    我们用一个系列来讲解从需求到上线.从代码到k8s部署.从日志到监控等各个方面的微服务完整实践. 整个项目使用了go-zero开发的微服务,基本包含了go-zero以及相关go-zero作者开发的一些中 ...

  9. 微服务从代码到k8s部署应有尽有系列(九、事务精讲)

    我们用一个系列来讲解从需求到上线.从代码到k8s部署.从日志到监控等各个方面的微服务完整实践. 整个项目使用了go-zero开发的微服务,基本包含了go-zero以及相关go-zero作者开发的一些中 ...

随机推荐

  1. 曼孚科技:“四管齐下”筑牢AI数据隐私安全防线

    谈及数据,绕不开的一个话题就是数据隐私与数据安全.随着数字化进程加快,数据安全事件频发,据Risk Based Security统计,去年国际数据泄露事件近5000起,被泄露数据近41亿条,数据造成的 ...

  2. 小程序onShareAppMessage有点迷

    小程序遇到的问题 起因 目前项目需求是分享时携带参数去进行裂变,但是在查看微信文档后发现有onShareAppMessage这个页面处理事件可以使用.事件可以使用return一个Object,用于自定 ...

  3. C#进阶——记一次USB HID的各种坑(x86,x64,win10,win7)

    一.简叙 写工控上位机的搬砖人,难免会遇到USB通讯,在一个项目中,我写的上位机使用USB HID协议和STM32通讯传输数据,从零大概花了几天找例程,找资料,最后是各种搬砖修补,终于出来了一个出版D ...

  4. Rust 连接 PostgreSQL 数据库

    这次,我们使用 postgres 这个 crate 来连接和操作 PostgreSQL 数据库. 创建好项目后,在 cargo.toml 里添加 postgres 的依赖: 首先,导入相关的类型,并创 ...

  5. k8s通过Service访问Pod

    如何创建服务 1.创建Deployment #启动三个pod,运行httpd镜像,label是run:mcw-httpd,Seveice将会根据这个label挑选PodapiVersion: apps ...

  6. python07day

    回顾 id == is: ==: 数值是否相同 is: 内存地址是否相同 id: 获取对象的内存地址 代码块: 一个文件.交互式命令一行都是一个代码块 同一代码块下缓存机制(字符串驻留机制) 所有数字 ...

  7. 学习Java第17天

    今天差不多搞清了Javaweb的基本学习路线及网站开发的基本流程,以前好像走了不少弯路,不过还好,明天开始学习Javaweb sql 总结了许多 新的学习方法,记笔记很重要,学多少忘多少. 练习也很重 ...

  8. makefile 编译多个目标

    1.静态库libtools.a源码 libtools.h #ifndef tools_h_ #define tools_h_ int sub(int x,int y); int mul(int x,i ...

  9. 【第十四期】高德go面经

    自我介绍 选一个比较熟悉的项目讲讲 筛选日志的时候,日志格式是不一样的,你们是如何处理的? 处理日志的时候如果日志量比较大会堆积吗?怎么处理的? 日志落盘到机器上,是如何采集的? 采集服务有问题的话可 ...

  10. linux 多个C源文件编译

    转载请注明来源:https://www.cnblogs.com/hookjc/ 如果有多个源文件,基本上有两种编译方法: [假设有两个源文件为test.c和testfun.c] 1. 多个文件一起编译 ...