小程序可以通过微信官方提供的登录能力方便地获取微信提供的用户身份标识,快速建立小程序内的用户体系。
系列云原生 API 网关,gRPC-Gateway V2 初探业务流程官方开发接入文档初始化项目开发环境为少
的本地开发环境
go version# go version go1.14.14 darwin/amd64protoc --version# libprotoc 3.15.7protoc-gen-go --version# protoc-gen-go v1.26.0protoc-gen-go-grpc --version# protoc-gen-go-grpc 1.1.0protoc-gen-grpc-gateway --version初始代码结构
使用 go mod init server
初始化 Go
项目,这里(demo
)我直接采用 server
作为当前 module
名字。
go-grpc-gateway-v2-microservice
├── auth // 鉴权微服务│ ├── API│ ├── ├── gen│ ├── ├── ├── v1 // 生成的代码将放到这里,v1 表示第一个 API 版本│ │ ├── auth.proto│ │ └── auth.yaml│ ├── auth│ │ └── auth.go // service 的具体实现│ ├── wechat │ └── main.go // 鉴权 gRPC server├── gateway // gRPC-Gateway,反向代理到各个 gRPC Server│ └── main.go├── gen.sh // 根据 `auth.proto` 生成代码的命令└── go.mod领域(auth.proto)定义
Syntax = "proto3";package auth.v1;option go_package="server/auth/API/gen/v1;authpb";// 客户端发送一个 codemessage LoginRequest { string code = 1;}// 开发者服务器返回一个自定义登录态(token)message LoginResponse { string access_token = 1; int32 expires_in = 2; // 按 oauth2 约定走}service AuthService { rpc Login (LoginRequest) returns (LoginResponse);}使用 gRPC-Gateway 暴露 RESTful JsON API
auth.yaml
定义type: Google.API.Serviceconfig_version: 3http: rules: - selector: auth.v1.AuthService.Login post: /v1/auth/login body: "*"根据配置生成代码使用
gen.sh
生成 gRPC-Gateway
相关代码PROTO_PATH=./auth/APIGO_OUT_PATH=./auth/API/gen/v1protoc -I=$PROTO_PATH --go_out=paths=source_relative:$GO_OUT_PATH auth.protoprotoc -I=$PROTO_PATH --go-grpc_out=paths=source_relative:$GO_OUT_PATH auth.protoprotoc -I=$PROTO_PATH --grpc-gateway_out=paths=source_relative,grpc_API_configuration=$PROTO_PATH/auth.yaml:$GO_OUT_PATH auth.proto
运行:
sh gen.sh
成功后,会生成 auth.pb.go
,auth_grpc.pb.go
,auth.pb.gw.go
文件,代码结构如下:
├── auth│ ├── API│ ├── ├── gen│ ├── ├── ├── v1│ ├── ├── ├── ├── auth.pb.go // 生成的 golang 相关的 protobuf 代码│ ├── ├── ├── ├── auth_grpc.pb.go // 生成 golang 相关的 gRPC Server 代码│ ├── ├── ├── ├── auth.pb.gw.go // 生成 golang 相关的 gRPC-Gateway 代码│ │ ├── auth.proto│ │ └── auth.yaml│ ├── auth│ │ └── auth.go│ ├── wechat │ └── main.go├── gateway│ └── main.go├── gen.sh└── go.mod
整理一下包:
go mod tIDy初步实现 Auth gRPC Service Server实现
AuthServiceServer
接口我们查看生成 auth_grpc.pb.go
代码,找到 AuthServiceServer
定义:
……// AuthServiceServer is the server API for AuthService service.// All implementations must embed UnimplementedAuthServiceServer// for forward compatibilitytype AuthServiceServer interface { Login(context.Context, *LoginRequest) (*LoginResponse, error) mustembedUnimplementedAuthServiceServer()}……
我们在 auth/auth/auth.go
进行它的实现:
关键代码解读:
// 定义 Service 结构体type Service struct { Logger *zap.Logger OpenIDResolver OpenIDResolver authpb.UnimplementedAuthServiceServer}// 这里作为使用者来说做一个抽象// 定义与微信第三方服务器通信的接口type OpenIDResolver interface { Resolve(code string) (string, error)}// 具体的方法实现func (s *Service) Login(c context.Context, req *authpb.LoginRequest) (*authpb.LoginResponse, error) { s.Logger.Info("received code", zap.String("code", req.Code)) // 调用微信服务器,拿到用户的唯一标识 openID openID, err := s.OpenIDResolver.Resolve(req.Code) if err != nil { return nil, status.Errorf(codes.Unavailable, "cannot resolve openID: %v", err) } // 调试代码,先这样写 return &authpb.LoginResponse{ Accesstoken: "token for open ID " + openID, ExpiresIn: 7200, }, nil}
这里有一个非常重要的编程理念,用好可以事半功倍。接口定义由使用者定义而不是实现者,如这里的 OpenIDResolver
接口。
OpenIDResolver
接口这里用到了社区的一个第三方库,这里主要用来完成开发者服务器向微信服务器换取 用户唯一标识 OpenID
、 用户在微信开放平台帐号下的唯一标识 UnionID
(若当前小程序已绑定到微信开放平台帐号) 和 会话密钥 session_key
。
当然,不用这个库,自己写也挺简单。
go get -u github.com/medivhzhan/weapp/v2
我们在 auth/wechat/wechat.go
进行它的实现:
关键代码解读:
// 相同的 Service 实现套路再来一遍// AppID & AppSecret 要可配置,是从外面传进来的type Service struct { AppID string AppSecret string}func (s *Service) Resolve(code string) (string, error) { resp, err := weapp.Login(s.AppID, s.AppSecret, code) if err != nil { return "", fmt.Errorf("weapp.Login: %v", err) } if err = resp.GetResponseError(); err != nil { return "", fmt.Errorf("weapp response error: %v", err) } return resp.OpenID, nil}配置 Auth Service gRPC Server
auth/main.go
func main() { logger, err := zap.NewDevelopment() if err != nil { log.Fatalf("cannot create logger: %v", err) } // 配置服务器监听端口 lis, err := net.Listen("tcp", ":8081") if err != nil { logger.Fatal("cannot Listen", zap.Error(err)) } // 新建 gRPC server s := grpc.NewServer() // 配置具体 Service authpb.RegisterauthServiceServer(s, &auth.Service{ OpenIDResolver: &wechat.Service{ AppID: "your-app-id", AppSecret: "your-app-secret", }, Logger: logger, }) // 对外开始服务 err = s.Serve(lis) if err != nil { logger.Fatal("cannot server", zap.Error(err)) }}初步实现 API Gateway
gateway/main.go
// 创建一个可取消的上下文(如:请求发到一半可随时取消)c := context.Background()c, cancel := context.WithCancel(c)defer cancel()mux := runtime.NewServeMux(runtime.WithMarshalerOption( runtime.MIMEWildcard, &runtime.JsONPb{ MarshalOptions: protoJson.MarshalOptions{ UseEnumNumbers: true, // 枚举字段的值使用数字 UseProtonames: true, // 传给 clIEnts 的 Json key 使用下划线 `_` // Accesstoken string `protobuf:"bytes,1,opt,name=access_token,Json=accesstoken,proto3" Json:"access_token,omitempty"` // 这里说明应使用 access_token }, UnmarshalOptions: protoJson.UnmarshalOptions{ discardUnkNown: true, // 忽略 clIEnt 发送的不存在的 poroto 字段 }, },))err := authpb.RegisterauthServiceHandlerFromEndpoint( c, mux, "localhost:8081", []grpc.DialOption{grpc.WithInsecure()},)if err != nil { log.Fatalf("cannot register auth service: %v", err)}err = http.ListenAndServe(":8080", mux)if err != nil { log.Fatalf("cannot Listen and server: %v", err)}测试
// 发送 res.code 到后台换取 openID, sessionKey, unionIDwx.request({ url: "http://localhost:8080/v1/auth/login", method: "POST", data: { code: res.code }, success: console.log, fail: console.error,})RefsDemo: go-grpc-gateway-v2-microservicegRPC-GatewaygRPC-Gateway Docs
我是为少微信:uuhells123公众号:***下午茶加我微信(互相学习交流),关注公众号(获取更多学习资料~)总结
以上是内存溢出为你收集整理的Go + gRPC-Gateway(V2) 构建微服务实战系列,小程序登录鉴权服务:第一篇(内附开发 demo)全部内容,希望文章能够帮你解决Go + gRPC-Gateway(V2) 构建微服务实战系列,小程序登录鉴权服务:第一篇(内附开发 demo)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)