当前位置: 首页 > news >正文

自己做视频网站流量钱桂林技术交流站

自己做视频网站流量钱,桂林技术交流站,青岛网站建设电话,中山免费企业网站建设1、gRPC认证 前面篇章的gRPC都是明文传输的#xff0c;容易被篡改数据#xff0c;本章将介绍如何为gRPC添加安全机制。 gRPC默认内置了两种认证方式#xff1a; SSL/TLS认证方式 基于Token的认证方式 同时#xff0c;gRPC提供了接口用于扩展自定义认证方式。 1.1 TLS…1、gRPC认证 前面篇章的gRPC都是明文传输的容易被篡改数据本章将介绍如何为gRPC添加安全机制。 gRPC默认内置了两种认证方式 SSL/TLS认证方式 基于Token的认证方式 同时gRPC提供了接口用于扩展自定义认证方式。 1.1 TLS认证 1.1.1 什么是TLS TLSTransport Layer Security安全传输层)TLS是建立在传输层TCP协议之上的协议服务于应用层它的前 身是SSLSecure Socket Layer安全套接字层它实现了将应用层的报文进行加密后再交由TCP进行传输的功 能。 1.1.2 TLS的作用 TLS协议主要解决如下三个网络安全问题。 保密(message privacy)保密通过加密encryption实现所有信息都加密传输第三方无法嗅探 完整性(message integrity)通过MAC校验机制一旦被篡改通信双方会立刻发现 认证(mutual authentication)双方认证,双方都可以配备证书防止身份被冒充 这里实现TLS认证机制首先需要准备证书在tls_demo目录新建keys目录用于存放证书文件。 1.1.3 证书制作 openSSL下载安装地址http://slproweb.com/products/Win32OpenSSL.html (1)、制作私钥 (server.key) # 生成RSA私钥 [rootzsx keys]# openssl genrsa -out server.key 2048 Generating RSA private key, 2048 bit long modulus ................. ................... e is 65537 (0x10001) # 或者可以生成ECC私钥 # 生成ECC私钥,命令为椭圆曲线密钥参数生成及操作,这里ECC曲线选择的是secp384r1 openssl ecparam -genkey -name secp384r1 -out server.key[rootzsx keys]# ls server.key(2)、自签名公钥(server.pem) 会生成serve.pem其中Common Name也就是域名我填的是xgrpc.com。 [rootzsx keys]# openssl req -new -x509 -sha256 -key server.key -out server.pem -days 3650 You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter ., the field will be left blank. ----- Country Name (2 letter code) [XX]:cn State or Province Name (full name) []:tj Locality Name (eg, city) [Default City]:tj Organization Name (eg, company) [Default Company Ltd]:ndty Organizational Unit Name (eg, section) []:ndty Common Name (eg, your name or your servers hostname) []:xgrpc.com Email Address []:2420309401qq.comopenssl req生成自签名证书-new指生成证书请求-sha256指使用sha256加密-key指定私钥文件-x509指输出证书-days 3650为有效期-out输出证书的文件名 [rootzsx keys]# ls server.key server.pem # 使用方式 # credentials.NewServerTLSFromFile(server.pem,server.key)上面的两个步骤是不带密码的可以生成带密码的这里只简单的列举命令具体的使用请参考下面SAN证书生 成 # 1、生成CA私钥(ca.key) openssl genrsa -des3 -out ca.key 2048 # 2、生成CA证书签名请求(ca.csr) openssl req -new -key ca.key -out ca.csr # 该命令需要输入密码,如果不想输入命令简单使用可以先执行下面的这条命令,在执行该命令 # 这条命令会去掉密码 # openssl rsa -in ca.key -out ca.key # 生成自签名CA证书(ca.cert) openssl x509 -req -days 3650 -in ca.csr -signkey ca.key -out ca.crt # 生成的ca.key和ca.crt就可以使用了 # credentials.NewServerTLSFromFile(ca.crt,ca.key)go1.15 版本开始废弃CommonName因此推荐使用SAN证书。 如果想兼容之前的方式需要设置环境变量 GODEBUG为 x509ignoreCN0。 否则将会运行报错 rpc error: code Unavailable desc connection error: desc transport: authentication handshake failed: x509: certificate relies on legacy Common Name field, use SANs or temporarily enable Common Name matching with GODEBUGx509ignoreCN01.1.4 使用openssl生成SAN证书 SAN(Subject Alternative Name)是 SSL 标准 x509 中定义的一个扩展。使用了 SAN 字段的 SSL 证书可以扩 展此证书支持的域名使得一个证书可以支持多个不同域名的解析。 由于Golang 1.17以上强制使用SAN证书故需要在此进行生成。 1、创建一个cert目录用于保存证书和配置文件。 2、创建配置文件(openssl.cnf)并保存到cert目录下内容如下 [CA_default] copy_extensions copy[req] distinguished_name req_distinguished_name x509_extensions v3_req prompt no[req_distinguished_name] # 国家 C CN # 省份 ST Shenzhen # 城市 L Shenzhen # 组织 O Arvin # 部门 OU Arvin # 域名 CN test.example.com[v3_req] basicConstraints CA:FALSE keyUsage nonRepudiation,digitalSignature,keyEncipherment subjectAltName alt_names[alt_names] # 解析域名 DNS.1 *.test.example.com # 可配置多个域名 DNS.2 *.example.com3、生成根证书rootCa 使用命令行工具进入到cert目录下并执行如下命令 # 生成私钥,密码可以输入123456 [rootzsx cert]# openssl genrsa -des3 -out ca.key 2048 Generating RSA private key, 2048 bit long modulus .......................................... .... e is 65537 (0x10001) Enter pass phrase for ca.key:123456 Verifying - Enter pass phrase for ca.key:123456# 使用私钥来签名证书 [rootzsx cert]# openssl req -new -key ca.key -out ca.csr Enter pass phrase for ca.key:123456 You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter ., the field will be left blank. ----- Country Name (2 letter code) [XX]:CN State or Province Name (full name) []:Shenzhen Locality Name (eg, city) [Default City]:Shenzhen Organization Name (eg, company) [Default Company Ltd]:Arvin Organizational Unit Name (eg, section) []:Arvin Common Name (eg, your name or your servers hostname) []:test.example.com Email Address []:2420309401qq.comPlease enter the following extra attributes to be sent with your certificate request A challenge password []: # 回车即可 An optional company name []: # 回车即可# 使用私钥证书来生成公钥 [rootzsx cert]# openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt Signature ok subject/CCN/STShenzhen/LShenzhen/OArvin/OUArvin/CNtest.example.com/emailAddress2420309401qq.com Getting Private key Enter pass phrase for ca.key:123456[rootzsx cert]# ls ca.crt ca.csr ca.key openssl.cnf4、在cert目录下分别创建server、client目录它们用来保存服务器密钥与客户端密钥。 5、生成服务器密钥 使用命令行工具进入到cert目录下并执行如下命令 # 生成服务器私钥 [rootzsx cert]# openssl genpkey -algorithm RSA -out server/server.key ................ ....# 使用私钥来签名证书 [rootzsx cert]# openssl req -new -nodes -key server/server.key -out server/server.csr -config openssl.cnf -extensions v3_req# 生成SAN证书 $ [rootzsx cert]# openssl x509 -req -in server/server.csr -out server/server.pem -CA ca.crt -CAkey ca.key -CAcreateserial -extfile ./openssl.cnf -extensions v3_req Signature ok subject/CCN/STShenzhen/LShenzhen/OArvin/OUArvin/CNtest.example.com Getting CA Private Key Enter pass phrase for ca.key:1234566、生成客户端密钥 使用命令行工具进入到cert目录下并执行如下命令 # 生成客户端私钥 [rootzsx cert]# openssl genpkey -algorithm RSA -out client/client.key ... ...# 使用私钥来签名证书 [rootzsx cert]# openssl req -new -nodes -key client/client.key -out client/client.csr -config openssl.cnf -extensions v3_req# 生成SAN证书 [rootzsx cert]# openssl x509 -req -in client/client.csr -out client/client.pem -CA ca.crt -CAkey ca.key -CAcreateserial -extfile ./openssl.cnf -extensions v3_req Signature ok subject/CCN/STShenzhen/LShenzhen/OArvin/OUArvin/CNtest.example.com Getting CA Private Key Enter pass phrase for ca.key:123456[rootzsx protoc]# tree tls_demo/ tls_demo/ └── cert├── ca.crt├── ca.csr├── ca.key├── ca.srl├── client│ ├── client.csr│ ├── client.key│ └── client.pem├── openssl.cnf└── server├── server.csr├── server.key└── server.pem3 directories, 11 files1.1.5 编写hello.proto // 指定proto版本 syntax proto3; // 指定包名 package hello; option go_package./hello;// 定义Hello服务 service Hello {// 定义SayHello方法rpc SayHello(HelloRequest) returns (HelloReply) {} }// HelloRequest 请求结构 message HelloRequest {string name 1; }// HelloReply 响应结构 message HelloReply {string message 1; }运行 [rootzsx tls_demo]# protoc --go_outpluginsgrpc:. hello.proto1.1.6 服务端server.go package mainimport (contextfmtpb tls_demo/hellogoogle.golang.org/grpc// 引入grpc认证包google.golang.org/grpc/credentialsnetlog )const (// Address gRPC服务地址Address 127.0.0.1:50052 )// 定义helloService并实现约定的接口 type helloService struct{}// HelloService Hello服务 var HelloService helloService{}// SayHello 实现Hello服务接口 func (h helloService) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {resp : new(pb.HelloReply)resp.Message fmt.Sprintf(Hello %s., in.Name)return resp, nil }func main() {log.Println(服务端启动!)listen, err : net.Listen(tcp, Address)if err ! nil {log.Fatalf(Failed to listen: %v, err)}// TLS认证creds, err : credentials.NewServerTLSFromFile(./cert/server/server.pem, ./cert/server/server.key)if err ! nil {log.Fatalf(Failed to generate credentials %v, err)}// 实例化grpc Server, 并开启TLS认证s : grpc.NewServer(grpc.Creds(creds))// 注册HelloServicepb.RegisterHelloServer(s, HelloService)log.Println(Listen on Address with TLS)s.Serve(listen) }credentials.NewServerTLSFromFile从输入证书文件和密钥文件为服务端构造TLS凭证 grpc.Creds返回一个ServerOption用于设置服务器连接的凭证。 运行 [rootzsx tls_demo]# go run server.go 2023/02/11 09:55:59 服务端启动! 2023/02/11 09:55:59 Listen on 127.0.0.1:50052 with TLS服务端在实例化grpc Server时可配置多种选项TLS认证是其中之一。 1.1.7 客户端client.go package mainimport (context// 引入proto包pb tls_demo/hellogoogle.golang.org/grpc// 引入grpc认证包google.golang.org/grpc/credentialslog )const (// Address gRPC服务地址Address 127.0.0.1:50052 )func main() {log.Println(客户端连接!)// TLS连接creds, err : credentials.NewClientTLSFromFile(./cert/server/server.pem, test.example.com)if err ! nil {log.Fatalf(Failed to create TLS credentials %v, err)}conn, err : grpc.Dial(Address, grpc.WithTransportCredentials(creds))if err ! nil {log.Fatalln(err:, err)}defer conn.Close()// 初始化客户端c : pb.NewHelloClient(conn)// 调用方法req : pb.HelloRequest{Name: gRPC}res, err : c.SayHello(context.Background(), req)if err ! nil {log.Fatalln(err)}log.Println(res.Message) }credentials.NewClientTLSFromFile从输入的证书文件中为客户端构造TLS凭证。 grpc.WithTransportCredentials配置连接级别的安全凭证例如TLS/SSL返回一个DialOption 用于连接服务器。 运行 [rootzsx tls_demo]# go run client.go 2023/02/11 10:00:11 客户端连接! 2023/02/11 10:00:11 Hello gRPC.客户端添加TLS认证的方式和服务端类似在创建连接Dial时同样可以配置多种选项后面的示例中会看到更 多的选项。 # 项目结构 [rootzsx protoc]# tree tls_demo/ tls_demo/ ├── cert │ ├── ca.crt │ ├── ca.csr │ ├── ca.key │ ├── ca.srl │ ├── client │ │ ├── client.csr │ │ ├── client.key │ │ └── client.pem │ ├── openssl.cnf │ └── server │ ├── server.csr │ ├── server.key │ └── server.pem ├── client.go ├── go.mod ├── go.sum ├── hello │ └── hello.pb.go ├── hello.proto └── server.go4 directories, 17 files1.2 Token认证 到这里已经完成TLS证书认证了gRPC传输不再是明文传输。此外添加自定义的验证方法能使gRPC相对更安 全。下面以TLS Token认证为例介绍gRPC如何添加自定义验证方法。 1.2.1 Token认证原理 客户端发请求时添加Token到上下文context.Context中服务器接收到请求先从上下文中获取Token验 证验证通过才进行下一步处理。 客户端请求添加Token到上下文中 conn, err : grpc.Dial(Address, grpc.WithTransportCredentials(creds), grpc.WithPerRPCCredentials(token))type PerRPCCredentials interface {GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error)RequireTransportSecurity() bool }gRPC 中默认定义了 PerRPCCredentials是提供用于自定义认证的接口它的作用是将所需的安全认证信息添 加到每个RPC方法的上下文中。其包含 2 个方法 GetRequestMetadata获取当前请求认证所需的元数据。RequireTransportSecurity是否需要基于 TLS 认证进行安全传输。 package authimport (context )// Token token认证 type Token struct {AppID stringAppSecret string }// GetRequestMetadata 获取当前请求认证所需的元数据 func (t *Token) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {return map[string]string{app_id: t.AppID, app_secret: t.AppSecret}, nil }// RequireTransportSecurity 是否需要基于 TLS 认证进行安全传输 func (t *Token) RequireTransportSecurity() bool {return true }//构建Token token : auth.Token{AppID: grpc_token,AppSecret: 123456, } // 连接服务器 conn, err : grpc.Dial(Address, grpc.WithTransportCredentials(creds),grpc.WithPerRPCCredentials(token))1.2.2 服务端tserver.go package mainimport (fmtpb tls_demo/hellogolang.org/x/net/contextgoogle.golang.org/grpcgoogle.golang.org/grpc/codesgoogle.golang.org/grpc/metadata// 引入grpc认证包google.golang.org/grpc/credentialslognet )const (// Address gRPC服务地址Address 127.0.0.1:50052 )// 定义helloService并实现约定的接口 type helloService struct{}// HelloService ... var HelloService helloService{}// SayHello 实现Hello服务接口 func (h helloService) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {// 解析metada中的信息并验证md, ok : metadata.FromIncomingContext(ctx)if !ok {return nil, grpc.Errorf(codes.Unauthenticated, 无Token认证信息)}// metadata: map[:authority:[test.example.com] appid:[101010] appkey:[I am key] content-type:[application/grpc] user-agent:[grpc-go/1.53.0]]log.Println(metadata: ,md)var (appid stringappkey string)if val, ok : md[appid]; ok {appid val[0]}if val, ok : md[appkey]; ok {appkey val[0]}if appid ! 101010 || appkey ! I am key {return nil, grpc.Errorf(codes.Unauthenticated, Token认证信息无效: appid%s, appkey%s, appid, appkey)}resp : new(pb.HelloReply)resp.Message fmt.Sprintf(Hello %s.\nToken info: appid%s,appkey%s, in.Name, appid, appkey)return resp, nil }func main() {listen, err : net.Listen(tcp, Address)if err ! nil {log.Fatalf(failed to listen: %v, err)}// TLS认证creds, err : credentials.NewServerTLSFromFile(./cert/server/server.pem, ./cert/server/server.key)if err ! nil {log.Fatalf(Failed to generate credentials %v, err)}// 实例化grpc Server, 并开启TLS认证s : grpc.NewServer(grpc.Creds(creds))// 注册HelloServicepb.RegisterHelloServer(s, HelloService)log.Println(Listen on Address with TLS Token)s.Serve(listen) }metadata.FromIncomingContext从上下文中获取元数据 运行 [rootzsx tls_demo]# go run tserver.go 2023/02/11 10:18:05 Listen on 127.0.0.1:50052 with TLS Token1.2.3 客户端tclient.go 这里我们定义了一个customCredential结构并实现了两个方法GetRequestMetadata和 RequireTransportSecurity。这是gRPC提供的自定义认证方式每次RPC调用都会传输认证信息。 customCredential其实是实现了grpc/credential包内的PerRPCCredentials接口。每次调用token信息会 通过请求的metadata传输到服务端。下面具体看一下服务端如何获取metadata中的信息。 package mainimport (context// 引入proto包pb tls_demo/hellogoogle.golang.org/grpc// 引入grpc认证包google.golang.org/grpc/credentialslog )const (// Address gRPC服务地址Address 127.0.0.1:50052// OpenTLS 是否开启TLS认证OpenTLS true )// customCredential 自定义认证 type customCredential struct{}// GetRequestMetadata 实现自定义认证接口 func (c customCredential) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {return map[string]string{appid: 101010,appkey: I am key,}, nil }// RequireTransportSecurity 自定义认证是否开启TLS func (c customCredential) RequireTransportSecurity() bool {return OpenTLS }func main() {var err errorvar opts []grpc.DialOptionif OpenTLS {// TLS连接creds, err : credentials.NewClientTLSFromFile(./cert/server/server.pem, test.example.com)if err ! nil {log.Fatalf(Failed to create TLS credentials %v, err)}opts append(opts, grpc.WithTransportCredentials(creds))} else {opts append(opts, grpc.WithInsecure())}// 使用自定义认证opts append(opts, grpc.WithPerRPCCredentials(new(customCredential)))conn, err : grpc.Dial(Address, opts...)if err ! nil {log.Fatalln(err)}defer conn.Close()// 初始化客户端c : pb.NewHelloClient(conn)// 调用方法req : pb.HelloRequest{Name: gRPC}res, err : c.SayHello(context.Background(), req)if err ! nil {log.Fatalln(err)}log.Println(res.Message) }运行结果 [rootzsx tls_demo]# go run tclient.go 2023/02/11 10:40:21 Hello gRPC. Token info: appid101010,appkeyI am key修改appkey的值为i am key验证认证失败结果 [rootzsx tls_demo]# go run tclient.go 2023/02/11 10:40:59 rpc error: code Unauthenticated desc Token认证信息无效: appid101010, appkeyi am key exit status 1# 项目结构 $ tree tls_demo/ tls_demo/ ├── cert │ ├── ca.crt │ ├── ca.csr │ ├── ca.key │ ├── ca.srl │ ├── client │ │ ├── client.csr │ │ ├── client.key │ │ └── client.pem │ ├── openssl.cnf │ └── server │ ├── server.csr │ ├── server.key │ └── server.pem ├── client.go ├── go.mod ├── go.sum ├── hello │ └── hello.pb.go ├── hello.proto ├── server.go ├── tclient.go └── tserver.go1.3 JWT认证 1.3.1 proto编写和编译 syntax proto3; package api; option go_package ./api;api;service Ping {rpc Login (LoginRequest) returns (LoginReply) {}rpc SayHello(PingMessage) returns (PingMessage) {} }message LoginRequest {string username 1;string password 2; }message LoginReply {string status 1;string token 2; }message PingMessage {string greeting 1; }$ protoc --go_outpluginsgrpc:. api/api.proto1.3.2 jwt工具类 /api/authtoken.go文件的内容如下 package apiimport (contextfmtgithub.com/dgrijalva/jwt-gogoogle.golang.org/grpc/metadatatime )// 生成token func CreateToken(userName string) (tokenString string) {token : jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{iss: lora-app-server,aud: lora-app-server,nbf: time.Now().Unix(),exp: time.Now().Add(time.Hour).Unix(),sub: user,username: userName,})tokenString, err : token.SignedString([]byte(verysecret))if err ! nil {panic(err)}return tokenString }// AuthToekn自定义认证 type AuthToekn struct {Token string }// AuthToekn实现了该方法,相当于实现了PerRPCCredentials接口 func (c AuthToekn) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {return map[string]string{authorization: c.Token,}, nil }// AuthToekn实现了该方法,相当于实现了PerRPCCredentials接口 // 是否验证证书 func (c AuthToekn) RequireTransportSecurity() bool {return false }// Claims defines the struct containing the token claims. type Claims struct {jwt.StandardClaims// Username defines the identity of the user.Username string json:username }// Step1. 从 context 的 metadata 中取出 token func getTokenFromContext(ctx context.Context) (string, error) {md, ok : metadata.FromIncomingContext(ctx)if !ok {return , fmt.Errorf(ErrNoMetadataInContext)}// md 的类型是 type MD map[string][]stringtoken, ok : md[authorization]if !ok || len(token) 0 {return , fmt.Errorf(ErrNoAuthorizationInMetadata)}// 因此token 是一个字符串数组我们只用了 token[0]return token[0], nil }func CheckAuth(ctx context.Context) (username string) {tokenStr, err : getTokenFromContext(ctx)if err ! nil {panic(get token from context error)}var clientClaims Claimstoken, err : jwt.ParseWithClaims(tokenStr, clientClaims, func(token *jwt.Token) (interface{}, error) {if token.Header[alg] ! HS256 {panic(ErrInvalidAlgorithm)}return []byte(verysecret), nil})if err ! nil {panic(jwt parse error)}if !token.Valid {panic(ErrInvalidToken)}fmt.Println(parse token is: , token)return clientClaims.Username }1.3.3 逻辑处理 api/handler.go文件的内容如下 package apiimport (fmtgolang.org/x/net/context )// Server represents the gRPC server type Server struct { }// 登录处理 func (s *Server) Login(ctx context.Context, in *LoginRequest) (*LoginReply, error) {fmt.Println(Loginrequest: , in.Username)if in.Username gavin in.Password gavin {// 创建jwttokenString : CreateToken(in.Username)fmt.Println(generate token is: , tokenString)return LoginReply{Status: 200, Token: tokenString}, nil} else {return LoginReply{Status: 403, Token: }, nil} }// SayHello generates response to a Ping request func (s *Server) SayHello(ctx context.Context, in *PingMessage) (*PingMessage, error) {msg : bar// 逻辑处理前需要验证jwtuserName : CheckAuth(ctx)msg userNamereturn PingMessage{Greeting: msg}, nil }1.3.4 服务端 package mainimport (demo/apifmtgoogle.golang.org/grpclognet )func main() {lis, err : net.Listen(tcp, fmt.Sprintf(:%d, 7777))if err ! nil {log.Fatalf(failed to listen: %v, err)}s : api.Server{}grpcServer : grpc.NewServer()api.RegisterPingServer(grpcServer, s)if err : grpcServer.Serve(lis); err ! nil {log.Fatalf(failed to serve: %s, err)} }$ go run server.go Loginrequest: gavin generate token is: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJsb3JhLWFwcC1zZXJ2ZXIiLCJleHAiOjE2NzY2MDE3MTgsImlzcyI6ImxvcmEtYXBwLXNlcnZlciIsIm5iZiI6MTY3NjU5ODExOCwic3ViIjoidXNlciIsInVzZXJuYW1lIjoiZ2F2aW4ifQ.IoAmUq2Vm90I5dWEgNEGc22c7YspVJN4cLeOWS16gaA parse token is: {eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJsb3JhLWFwcC1zZXJ2ZXIiLCJleHAiOjE2NzY2MDE3MTgsImlzcyI6ImxvcmEtYXBwLXNlcnZlciIsIm5iZiI6MTY3NjU5ODExOCwic3ViIjoidXNlciIsInVzZXJuYW1lIjoiZ2F2aW4ifQ.IoAmUq2Vm90I5dWEgNEGc22c7YspVJN4cLeOWS16gaA 0xc00000e600 map[alg:HS256 typ:JWT] 0xc0001684d0 IoAmUq2Vm90I5dWEgNEGc22c7YspVJN4cLeOWS16gaA true}1.3.5 客户端 package mainimport (contextdemo/apifmtgoogle.golang.org/grpclog )func main() {var conn *grpc.ClientConnconn, err : grpc.Dial(:7777, grpc.WithInsecure())if err ! nil {log.Fatalf(did not connect: %s, err)}defer conn.Close()c : api.NewPingClient(conn)loginReply, err : c.Login(context.Background(), api.LoginRequest{Username: gavin, Password: gavin})if err ! nil {log.Fatalf(Error when calling SayHello: %s, err)}fmt.Println(Login Reply:, loginReply)//Call SayHellorequestToken : new(api.AuthToekn)requestToken.Token loginReply.Tokenconn, err grpc.Dial(:7777, grpc.WithInsecure(), grpc.WithPerRPCCredentials(requestToken))if err ! nil {log.Fatalf(did not connect: %s, err)}defer conn.Close()c api.NewPingClient(conn)helloreply, err : c.SayHello(context.Background(), api.PingMessage{Greeting: foo})if err ! nil {log.Fatalf(Error when calling SayHello: %s, err)}log.Printf(Response from server: %s, helloreply.Greeting) }$ go run client.go Login Reply: status:200 token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJsb3JhLWFwcC1zZXJ2ZXIiLCJleHAiOjE2NzY2MDE3MTgsImlzcyI6ImxvcmEtYXBwLXNlcnZlciIsIm5iZiI6MTY3NjU5ODExOCwic3ViIjoidXNlciIsInVzZXJuYW1lIjoiZ2F2aW4ifQ.IoAmUq2Vm90I5dWEgNEGc22c7YspVJN4cLeOWS16gaA 2023/02/17 09:41:58 Response from server: bar gavin# 项目结构 $ tree demo/ demo/ ├── api │ ├── api.pb.go │ ├── api.proto │ ├── authtoken.go │ └── handler.go ├── client1.go ├── echo.proto ├── go.mod ├── go.sum ├── proto │ └── echo.pb.go └── server1.go2 directories, 10 filesgoogle.golang.org/grpc/credentials/oauth包已实现了用于Google API的oauth和jwt验证的方法使用方 法可以参考[官方文档] https://github.com/grpc/grpc-go/blob/master/Documentation/grpc-auth-support.md 在实际应用中我们可以根据自己的业务需求实现合适的验证方式。 1.4 oauth认证 1.4.1 proto编写和编译 syntax proto3; option go_package ./proto; package proto;message EchoRequest {string message 1; }message EchoResponse {string message 1; }service Echo {rpc UnaryEcho(EchoRequest) returns (EchoResponse) {}rpc ServerStreamingEcho(EchoRequest) returns (stream EchoResponse) {}rpc ClientStreamingEcho(stream EchoRequest) returns (EchoResponse) {}rpc BidirectionalStreamingEcho(stream EchoRequest) returns (stream EchoResponse) {} }$ protoc --go_outpluginsgrpc:. echo.proto1.4.2 服务端编写 package mainimport (contextcrypto/tlspb demo/proto/protoflagfmtgoogle.golang.org/grpcgoogle.golang.org/grpc/codesgoogle.golang.org/grpc/credentialsgoogle.golang.org/grpc/metadatagoogle.golang.org/grpc/statuslognetstrings )var (errMissingMetadata status.Errorf(codes.InvalidArgument, missing metadata)errInvalidToken status.Errorf(codes.Unauthenticated, invalid token) )var port flag.Int(port, 50051, the port to serve on)func main() {flag.Parse()fmt.Printf(server starting on port %d...\n, *port)cert, err : tls.LoadX509KeyPair(./cert/server/server.pem, ./cert/server/server.key)if err ! nil {log.Fatalf(failed to load key pair: %s, err)}opts : []grpc.ServerOption{grpc.UnaryInterceptor(ensureValidToken),grpc.Creds(credentials.NewServerTLSFromCert(cert)),}s : grpc.NewServer(opts...)pb.RegisterEchoServer(s, ecServer{})lis, err : net.Listen(tcp, fmt.Sprintf(:%d, *port))if err ! nil {log.Fatalf(failed to listen: %v, err)}if err : s.Serve(lis); err ! nil {log.Fatalf(failed to serve: %v, err)} }type ecServer struct {pb.UnimplementedEchoServer }func (s *ecServer) UnaryEcho(ctx context.Context, req *pb.EchoRequest) (*pb.EchoResponse, error) {return pb.EchoResponse{Message: req.Message}, nil }func valid(authorization []string) bool {if len(authorization) 1 {return false}token : strings.TrimPrefix(authorization[0], Bearer )return token some-secret-token }func ensureValidToken(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {md, ok : metadata.FromIncomingContext(ctx)if !ok {return nil, errMissingMetadata}if !valid(md[authorization]) {return nil, errInvalidToken}return handler(ctx, req) }[rootzsx demo]# go run server.go server starting on port 50051...1.4.3 客户端编写 package mainimport (contextecpb demo/proto/protoflagfmtgolang.org/x/oauth2google.golang.org/grpcgoogle.golang.org/grpc/credentialsgoogle.golang.org/grpc/credentials/oauthlogtime )var addr flag.String(addr, localhost:50051, the address to connect to)func callUnaryEcho(client ecpb.EchoClient, message string) {ctx, cancel : context.WithTimeout(context.Background(), 10*time.Second)defer cancel()resp, err : client.UnaryEcho(ctx, ecpb.EchoRequest{Message: message})if err ! nil {log.Fatalf(client.UnaryEcho(_) _, %v: , err)}fmt.Println(UnaryEcho: , resp.Message) }func main() {flag.Parse()perRPC : oauth.TokenSource{TokenSource: oauth2.StaticTokenSource(fetchToken())}creds, err : credentials.NewClientTLSFromFile(./cert/server/server.pem, x.test.example.com)if err ! nil {log.Fatalf(failed to load credentials: %v, err)}opts : []grpc.DialOption{grpc.WithPerRPCCredentials(perRPC),grpc.WithTransportCredentials(creds),}conn, err : grpc.Dial(*addr, opts...)if err ! nil {log.Fatalf(did not connect: %v, err)}defer conn.Close()rgc : ecpb.NewEchoClient(conn)callUnaryEcho(rgc, hello world) }func fetchToken() *oauth2.Token {return oauth2.Token{AccessToken: some-secret-token,} }[rootzsx demo]# go run client.go UnaryEcho: hello world# 项目结构 [rootzsx protoc]# tree demo/ demo/ ├── cert │ ├── ca.crt │ ├── ca.csr │ ├── ca.key │ ├── ca.srl │ ├── client │ │ ├── client.csr │ │ ├── client.key │ │ └── client.pem │ ├── openssl.cnf │ └── server │ ├── server.csr │ ├── server.key │ └── server.pem ├── client.go ├── go.mod ├── go.sum ├── proto │ ├── echo.proto │ └── proto │ └── echo.pb.go └── server.go5 directories, 17 files参考地址https://godoc.org/google.golang.org/grpc/credentials/oauth
http://www.huolong8.cn/news/47850/

相关文章:

  • 网站建设干货图书网站开发尾款如何做账
  • 阿里云购买域名后怎么建网站那里做网站好
  • 网站建设项目的摘要南宁关键词优化软件
  • wordpress建站更换图片提交网站
  • 郑州网站开发douyanet对网站建设的考核机制
  • 陕西网站建设网络培训心得体会总结简短
  • 网站建设公司net2006关键词优化策略有哪些
  • 精通网站建设pdf下载母婴类网站 网站建设方案书 备案
  • pos机做网站推广如何在wordpress上下载apk
  • 网站地图模板响应式网站设计开发
  • 做网站版头图片企业商务网站 建设方案
  • app优化网站网站管理制度规范
  • 西安商城网站建设长沙可以做网站的公司
  • 免费网站建设阿里网站
  • 织梦html5手机网站模板松江车墩网站建设
  • 做网站一般分几种济南轻电商网站建设公司
  • 淘宝网网站建设的的意见高校二级网站建设意义
  • 腾讯云网站建设教学视频教程网站建设怎么分析市场
  • 优秀的国外网站设计网站科技有限公司经营范围
  • 网站正在建设中9797qq推广文案怎么写
  • 梅州网站建wordpress无限加载插件
  • 克隆网站后怎么做高端网站设计技术分析
  • 员工支付做网站的费用分录手机移动网站开发
  • 为男人做购物网站中职网站建设与维护试卷
  • 网站降权 烦it运维体系
  • 重庆宣网站建设贵州网络推广咨询
  • 海门建设厅网站wordpress怎么备案
  • 苍溪建设局网站南宁微信网站制作
  • 卖高仿名牌手表网站网站开发哪里好
  • 关于asp sql网站开发的书籍做营利网站的风险