刘沙河 刘沙河
首页
  • Go语言基础

    • 数据类型
    • 反射
    • Go指针
  • Go语言进阶

    • go泛型
    • go条件编译
    • cgo教程
    • Go协程调度原理及GPM模型
    • Go内存管理
    • Go垃圾回收机制
    • Go语言内存对齐
  • Go语言实现原理

    • channel 实现原理
    • slice 实现原理
    • map 实现原理
    • sync.Mutex 实现原理
    • 乐观锁CAS 实现原理
    • singlefight 实现原理
  • gin框架

    • gin中间件原理
    • gin路由原理
  • gorm

    • GORM介绍和使用
    • GORM_CURD操作指南
  • go测试

    • benchmark基准测试
    • pprof 性能分析
  • python进阶

    • Numpy&Pandas
    • celery分布式任务队列
  • Django

    • Django 常见命令
    • middleware中间件
    • Django缓存系统
    • Django信号系统
    • Django REST Framework
  • Flask

    • Flask基础知识总结
    • Flask-SQLAlchemy
  • 爬虫

    • aiohttp
    • scrapy框架
  • Mysql

    • Mysql存储引擎和索引
    • MySQL主从复制
    • Mysql读写分离
    • 数据库分库分表
    • Mysql锁
    • Mysql事务和MVCC原理
    • 分库分表带来的读扩散问题
  • Redis

    • redis基础和数据类型
    • redis主从架构
    • redis哨兵架构
    • redis集群模式
    • 如何保证缓存和数据库双写一致
    • redis底层数据结构
    • redis分布式锁
  • Elasticsearch

    • es基本概念
    • es基础语法
    • es倒排索引
  • etcd

    • Go操作etcd
    • Raft原理
    • etcd分布式锁
  • kafka

    • 消息队列MQ总结
    • kafka 概述及原理
    • kafka 消费问题记录
    • 零拷贝技术
    • kafka分区规范
  • RabbitMQ

    • rabbitMQ基础
    • Go操作rabbitmq
  • RocketMQ

    • 可靠消息队列 rocketMQ
  • Http&Https

    • http&https
    • TCP和UDP
    • Ping 原理
  • RPC

    • RPC初识
    • grpc初识和实现
  • gRPC

    • grpc 初识
    • grpc 上下文 metadata
    • grpc 健康检查
    • grpc keepalive
    • grpc 命名解析
    • grpc 中间件&拦截器
    • grpc 负载均衡
    • grpc 身份认证
    • grpc 超时重试
    • grpc 链路追踪
    • grpc-gw将gRPC转RESTfu api
    • grpc-gw自定义选项
  • protobuf

    • protobuf 进阶
    • protobuf 编码原理
  • Docker

    • Docker基础
    • Docker常用命令
    • Dockerfile
    • Docker-Compose
    • Docker多阶段构建
    • Docker Config 教程
    • Docker Swarm 教程
    • Docker Stack 教程
    • Docker Buildx 教程
  • k8s

    • k8s 基础概念
    • k8s 集群架构
    • k8s 工作负载
    • Pod 网络
    • Service 网络
    • 外部接入网络
    • 一张图搞懂k8s各种pod
    • k8s 存储抽象
    • mac快速启动k8s
    • 自制申威架构k8s-reloader
  • go-kit

    • go-kit初识
    • go-kit启动http服务
    • go-kit集成gin启动服务
    • go-kit集成grpc和protobuf
    • go-kit中间件
    • go-kit服务注册发现与负载均衡
    • go-kit限流和熔断
    • go-kit链路追踪
    • go-kit集成Prometheus
  • 设计模式

    • 初识设计模式
    • 创建型模式
    • 结构型模式
    • 行为模式
  • 数据结构

    • 时间轮
    • 堆、双向链表、环形队列
    • 队列:优先队列
    • 队列:延迟队列
  • 算法

    • 递归算法
    • 枚举算法
    • 动态规划
    • 回溯算法
    • 分治算法
    • 贪心算法
    • LRU和LFU
    • 一致性哈希

花开半夏,半夏花开
首页
  • Go语言基础

    • 数据类型
    • 反射
    • Go指针
  • Go语言进阶

    • go泛型
    • go条件编译
    • cgo教程
    • Go协程调度原理及GPM模型
    • Go内存管理
    • Go垃圾回收机制
    • Go语言内存对齐
  • Go语言实现原理

    • channel 实现原理
    • slice 实现原理
    • map 实现原理
    • sync.Mutex 实现原理
    • 乐观锁CAS 实现原理
    • singlefight 实现原理
  • gin框架

    • gin中间件原理
    • gin路由原理
  • gorm

    • GORM介绍和使用
    • GORM_CURD操作指南
  • go测试

    • benchmark基准测试
    • pprof 性能分析
  • python进阶

    • Numpy&Pandas
    • celery分布式任务队列
  • Django

    • Django 常见命令
    • middleware中间件
    • Django缓存系统
    • Django信号系统
    • Django REST Framework
  • Flask

    • Flask基础知识总结
    • Flask-SQLAlchemy
  • 爬虫

    • aiohttp
    • scrapy框架
  • Mysql

    • Mysql存储引擎和索引
    • MySQL主从复制
    • Mysql读写分离
    • 数据库分库分表
    • Mysql锁
    • Mysql事务和MVCC原理
    • 分库分表带来的读扩散问题
  • Redis

    • redis基础和数据类型
    • redis主从架构
    • redis哨兵架构
    • redis集群模式
    • 如何保证缓存和数据库双写一致
    • redis底层数据结构
    • redis分布式锁
  • Elasticsearch

    • es基本概念
    • es基础语法
    • es倒排索引
  • etcd

    • Go操作etcd
    • Raft原理
    • etcd分布式锁
  • kafka

    • 消息队列MQ总结
    • kafka 概述及原理
    • kafka 消费问题记录
    • 零拷贝技术
    • kafka分区规范
  • RabbitMQ

    • rabbitMQ基础
    • Go操作rabbitmq
  • RocketMQ

    • 可靠消息队列 rocketMQ
  • Http&Https

    • http&https
    • TCP和UDP
    • Ping 原理
  • RPC

    • RPC初识
    • grpc初识和实现
  • gRPC

    • grpc 初识
    • grpc 上下文 metadata
    • grpc 健康检查
    • grpc keepalive
    • grpc 命名解析
    • grpc 中间件&拦截器
    • grpc 负载均衡
    • grpc 身份认证
    • grpc 超时重试
    • grpc 链路追踪
    • grpc-gw将gRPC转RESTfu api
    • grpc-gw自定义选项
  • protobuf

    • protobuf 进阶
    • protobuf 编码原理
  • Docker

    • Docker基础
    • Docker常用命令
    • Dockerfile
    • Docker-Compose
    • Docker多阶段构建
    • Docker Config 教程
    • Docker Swarm 教程
    • Docker Stack 教程
    • Docker Buildx 教程
  • k8s

    • k8s 基础概念
    • k8s 集群架构
    • k8s 工作负载
    • Pod 网络
    • Service 网络
    • 外部接入网络
    • 一张图搞懂k8s各种pod
    • k8s 存储抽象
    • mac快速启动k8s
    • 自制申威架构k8s-reloader
  • go-kit

    • go-kit初识
    • go-kit启动http服务
    • go-kit集成gin启动服务
    • go-kit集成grpc和protobuf
    • go-kit中间件
    • go-kit服务注册发现与负载均衡
    • go-kit限流和熔断
    • go-kit链路追踪
    • go-kit集成Prometheus
  • 设计模式

    • 初识设计模式
    • 创建型模式
    • 结构型模式
    • 行为模式
  • 数据结构

    • 时间轮
    • 堆、双向链表、环形队列
    • 队列:优先队列
    • 队列:延迟队列
  • 算法

    • 递归算法
    • 枚举算法
    • 动态规划
    • 回溯算法
    • 分治算法
    • 贪心算法
    • LRU和LFU
    • 一致性哈希
  • rpc

  • grpc

    • 【grpc】1.初识
    • 【grpc】2.上下文 metadata
    • 【grpc】3.健康检查
    • 【grpc】 4.keepalive
    • 【grpc】 5.命名解析
    • 【grpc】 6.中间件&拦截器
    • 【grpc】 7.负载均衡
    • 【grpc】 8.身份认证
      • 官方实现
        • 1. token认证示例
      • 2. TLS 证书认证
        • 3. Oauth认证
        • 3.1 oauth认证
        • 3.2 Oauth2 认证
    • 【grpc】 9.超时重试
    • 【grpc】 10.链路追踪
    • 【grpc】11.grpc-gw将gRPC 转 RESTful api
    • 【grpc】12.grpc-gw自定义选项
  • protobuf

  • rpc+grpc
  • grpc
bigox
2023-04-27
目录

【grpc】 8.身份认证

  • 在 gRPC 中,可以使用多种不同的认证方式来实现安全通信。以下是常用的认证方式:
    • TLS 证书认证:使用 TLS 证书验证服务器和客户端身份。TLS 证书认证是最常见的 gRPC 认证方式,它提供了强大的安全性和可靠性。这种方式需要服务端和客户端都拥有自己的 TLS 证书,并且使用这些证书进行身份验证。
    • Token 认证:使用 Token 验证客户端身份。Token 认证是比较简单的一种认证方式,可以用于快速验证客户端身份,但安全性不如 TLS 证书认证。
    • OAuth2 认证:使用 OAuth2 协议进行身份验证。OAuth2 认证是一种比较灵活的认证方式,可以使用多种不同的 OAuth2 提供者进行身份验证。

# 官方实现

https://pkg.go.dev/google.golang.org/grpc/credentials?utm_source=godoc

  • 包名:google.golang.org/grpc/credentials

    • 默认实现的认证方式
      1. alts:是由 Google 开发的一种应用层传输安全协议,可以用于保护 gRPC 客户端和服务器之间的通信。ALTS 支持云环境中的认证和授权,并提供了类似于 TLS 的功能,如握手、证书验证和加密
      2. google认证
      3. oauth:一种开放标准,用于授权第三方应用程序访问资源。可以通过 OAuth 进行 gRPC 客户端和服务器之间的身份验证和授权,使用 OAuth2 协议时,需要先创建一个 OAuth2 客户端应用程序,并获取相应的客户端 ID 和客户端密钥。
      4. sts:是一种由 AWS 提供的云服务,可以用于生成、验证和管理安全令牌。可以通过 STS 进行 gRPC 客户端和服务器之间的身份验证和授权,使用 STS 需要在 AWS 上创建一个 IAM 用户,并获取相应的 Access Key ID 和 Secret Access Key。
      5. tls
      6. cxds: 由 Istio 开发的一种服务网格认证机制,可以用于保护 gRPC 服务。CxDS 使用证书对客户端和服务器进行身份验证,并使用 mTLS(mutual TLS)来加密通信。
      7. 自定义
    • google.golang.org/grpc/credentials 包提供了一组接口和函数,用于实现 gRPC 中的安全传输机制和身份验证。通过使用这些接口和函数,我们可以轻松地实现不同类型的认证方式,以提高 gRPC 的安全性和可靠性。常用的认证方式包括 TLS 证书认证、Token 认证和 OAuth2 认证。
  • 常用的接口和函数:

    • credentials.TransportCredentials:定义了安全传输机制的接口。可以使用该接口来创建一个安全传输机制,如 TLS 证书传输机制。
    • credentials.PerRPCCredentials:定义了客户端身份验证的接口。可以使用该接口来实现 Token 认证或 OAuth2 认证。
    • credentials.NewClientTLSFromFile:用于创建一个基于证书的安全传输机制。该函数需要传入一个服务器的证书文件和一个 CA 证书文件。
    • credentials.NewServerTLSFromFile:用于创建一个基于证书的安全传输机制。该函数需要传入一个服务器的证书文件和一个服务器的私钥文件。

# 1. token认证示例

  • 客户端(或者使用metadata直接传输

    • MyTokenCredentials 自定义凭证,实现了 credentials.PerRPCCredentials 接口中的两个方法。GetRequestMetadata 方法返回一个包含认证信息的 map,RequireTransportSecurity 方法返回一个布尔值,表示是否要求使用安全传输。使用 grpc.Dial 函数创建了一个 gRPC 连接,并将 MyTokenCredentials 作为参数传入 grpc.WithPerRPCCredentials 函数,以实现 Token 认证。
    package main
    
    import (
    	helloproto "bigox-rpc/proto"
    	"context"
    	"fmt"
    	"google.golang.org/grpc"
    )
    
    // 创建一个基于 Token 的自定义凭证
    type MyTokenCredentials struct {
    	Token string
    }
    
    func (c *MyTokenCredentials) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
    	return map[string]string{
    		"token": c.Token,
    	}, nil
    }
    
    func (c *MyTokenCredentials) RequireTransportSecurity() bool {
    	return false
    }
    
    func main() {
    	conn, err := grpc.Dial(
    		"127.0.0.1:8080",
    		grpc.WithPerRPCCredentials(&MyTokenCredentials{Token: "token123"}),
    		grpc.WithInsecure(),
    	)
    
    	if err != nil {
    		panic(err)
    	}
    	defer conn.Close()
    	c := helloproto.NewGreeterClient(conn)
    	res, err := c.Hello(context.Background(), &helloproto.Req{Msg: "liushahe"})
    	if err != nil {
    		panic(err)
    	}
    	fmt.Println(res.Msg)
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
  • server

    
    		grpc.ChainUnaryInterceptor(func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
    			md, ok := metadata.FromIncomingContext(ctx)
    			if !ok {
    				return nil, fmt.Errorf("missing metadata")
    			}
    			if len(md["token"]) == 0 || md["token"][0] != "my-secret-token" {
    				return nil, fmt.Errorf("invalid token")
    			}
    			// todo
    			res, err := handler(ctx, req)
    			return res, err
    		}),
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

# 2. TLS 证书认证

TLS 证书认证是一种基于证书的认证方式,用于保护 gRPC 通信的安全性。

在 TLS 证书认证中,gRPC 客户端和服务器之间的通信通过 TLS 连接加密和验证。gRPC 服务器使用证书来证明其身份,而 gRPC 客户端使用证书来验证服务器的身份。通过 TLS 证书认证,可以有效地保护 gRPC 通信的安全性和可靠性。

  • server

    package main
    
    import (
    	"context"
    	"log"
    	"net"
    
    	"google.golang.org/grpc"
    	"google.golang.org/grpc/credentials"
    )
    
    type HelloServiceImpl struct{}
    
    func (s *HelloServiceImpl) SayHello(ctx context.Context, request *HelloRequest) (*HelloResponse, error) {
    	return &HelloResponse{Message: "Hello " + request.Name}, nil
    }
    
    func main() {
    	// 加载证书
    	creds, err := credentials.NewServerTLSFromFile("server.crt", "server.key")
    	if err != nil {
    		log.Fatalf("failed to load credentials: %v", err)
    	}
    
    	// 监听端口
    	listener, err := net.Listen("tcp", ":50051")
    	if err != nil {
    		log.Fatalf("failed to listen: %v", err)
    	}
    
    	// 创建 gRPC 服务器,启用 TLS 证书认证
    	server := grpc.NewServer(grpc.Creds(creds))
    	RegisterHelloServiceServer(server, &HelloServiceImpl{})
    
    	log.Println("server is running...")
    	if err := server.Serve(listener); err != nil {
    		log.Fatalf("failed to serve: %v", err)
    	}
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
  • client.go

    package main
    
    import (
    	"context"
    	"fmt"
    	"log"
    
    	"google.golang.org/grpc"
    	"google.golang.org/grpc/credentials"
    )
    
    func main() {
    	// 加载证书
    	creds, err := credentials.NewClientTLSFromFile("server.crt", "")
    	if err != nil {
    		log.Fatalf("failed to load credentials: %v", err)
    	}
    
    	// 创建 gRPC 连接
    	conn, err := grpc.Dial("localhost:50051", grpc.WithTransportCredentials(creds))
    	if err != nil {
    		log.Fatalf("failed to dial: %v", err)
    	}
    	defer conn.Close()
    
    	// 创建客户端
    	client := NewHelloServiceClient(conn)
    
    	// 发送请求
    	request := &HelloRequest{Name: "world"}
    	response, err := client.SayHello(context.Background(), request)
    	if err != nil {
    		log.Fatalf("failed to call SayHello: %v", err)
    	}
    	fmt.Println(response.Message)
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37

# 3. Oauth认证

# 3.1 oauth认证

  • server端只需要校验token即可

  • client

    import (
        "context"
        "fmt"
    
        "google.golang.org/grpc"
        "google.golang.org/grpc/credentials"
        "google.golang.org/grpc/credentials/oauth"
    )
    
    func main() {
        // 使用 OAuth Token 认证
        perRPC := oauth.TokenSource{
            TokenSource: myTokenSource, // 自定义的 TokenSource
        }
    
        creds := credentials.NewTLS(&tls.Config{})
        opts := []grpc.DialOption{
            grpc.WithTransportCredentials(creds),
            grpc.WithPerRPCCredentials(perRPC),
        }
    
        // 建立连接
        conn, err := grpc.Dial("localhost:50051", opts...)
        if err != nil {
            fmt.Printf("Failed to connect: %v", err)
            return
        }
        defer conn.Close()
    
        // TODO: 调用 gRPC 服务的代码
    }
    
    // 自定义 TokenSource,用于获取 OAuth Token
    func myTokenSource() (string, error) {
        // TODO: 实现获取 OAuth Token 的逻辑
        return "mytoken", nil
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38

# 3.2 Oauth2 认证

  • client

    package main
    
    import (
    	helloproto "bigox-rpc/proto"
    	"context"
    	"fmt"
    	"golang.org/x/oauth2"
    	"google.golang.org/grpc"
    	"google.golang.org/grpc/credentials/oauth"
    	"time"
    )
    
    func main() {
    	// 创建 OAuth2 客户端应用程序
    	oauthConfig := &oauth2.Config{
    		ClientID:     "my_client_id",
    		ClientSecret: "my_client_secret",
    		RedirectURL:  "http://localhost:8080/callback",
    		Scopes:       []string{"my_scope"},
    		Endpoint: oauth2.Endpoint{
    			AuthURL:  "https://oauth.example.com/authorize",
    			TokenURL: "https://oauth.example.com/token",
    		},
    	}
    	// 获取 OAuth2.0 Token
    	token, err := getToken(oauthConfig)
    	if err != nil {
    		fmt.Printf("Failed to get token: %v", err)
    		return
    	}
    	// 使用 OAuth2.0 Token 认证
    	perRPC := oauth.TokenSource{
    		TokenSource: oauthConfig.TokenSource(context.Background(), token),
    	}
    
    	conn, err := grpc.Dial(
    		"127.0.0.1:8080",
    		grpc.WithPerRPCCredentials(perRPC),
    		grpc.WithInsecure(),
    	)
    
    	if err != nil {
    		panic(err)
    	}
    	defer conn.Close()
    	c := helloproto.NewGreeterClient(conn)
    	res, err := c.Hello(context.Background(), &helloproto.Req{Msg: "liushahe"})
    	if err != nil {
    		panic(err)
    	}
    	fmt.Println(res.Msg)
    }
    
    // 获取 OAuth2.0 Token
    func getToken(config *oauth2.Config) (*oauth2.Token, error) {
    	// TODO: 实现获取 OAuth2.0 Token 的逻辑
    	return &oauth2.Token{
    		AccessToken:  "my_token",
    		RefreshToken: "my_refresh_token",
    		Expiry:       time.Now().Add(time.Hour),
    	}, nil
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
#grpc
上次更新: 2023/05/04, 15:30:48
【grpc】 7.负载均衡
【grpc】 9.超时重试

← 【grpc】 7.负载均衡 【grpc】 9.超时重试→

最近更新
01
go与http代理
05-24
02
自制申威架构k8s-reloader
12-06
03
Docker Buildx 教程
12-01
更多文章>
Theme by Vdoing | Copyright © 2020-2024 小刘扎扎 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式