grpc介绍(二)——认证方式

这篇具有很好参考价值的文章主要介绍了grpc介绍(二)——认证方式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

HTTP是明文传输的,即客户端与服务端之间通信的信息是可见的,这就存在被窃听、冒充或篡改的风险。HTTPS在HTTP和TCP之间加入了TLS协议,如图所示:

grpc介绍(二)——认证方式

TLS协议主要解决了以下三个网络安全问题:

  • 信息加密: HTTP 交互信息是被加密的,第三方就无法被窃取;
  • 校验机制:校验信息传输过程中是否有被第三方篡改过,如果被篡改过,则会有警告提示;
  • 身份证书:双方认证,双方都可以配置证书,防止身份被冒充;

客户端与服务端通过gRPC进行方法调用,也需要加入证书来保证调用的安全。

生成自签证书

安装openssl

# 下载openssl --- Win64 OpenSSL v3.0.5
https://slproweb.com/products/Win32OpenSSL.html

# 添加环境变量,将openssl.exe所在路径加入系统环境变量
C:\Program Files\OpenSSL-Win64\bin

生成私钥文件

openssl genrsa -des3 -out ca.key 2048

创建证书请求

openssl req -new -key ca.key -out ca.csr

生成ca.crt

openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt

修改openssl.cnf

# 打开copy_extensions
copy_extensions = copy

# 打开req_extensions
req_extensions = v3_req

# 找到[ v3_req ], 添加
subjectAltName = @alt_names

# 添加标签
[ alt_names ]
DNS.1 = *.dong.com

生成证书私钥

openssl genpkey -algorithm RSA -out server.key

通过私钥生成证书请求文件

openssl req -new -nodes -key server.key -out server.csr -days 3650 -config ./openssl.cnf -extensions v3_req

生成SAN证书

openssl x509 -req -days 365 -in server.csr -out server.pem -CA ca.crt -CAkey ca.key -CAc
reateserial -extfile ./openssl.cnf -extensions v3_req

说明:

  • key:服务器上的私钥文件,用于对发送给客户端数据的加密,以及对从客户端接收到数据的解密;
  • csr:证书签名请求文件,用于提交给证书颁发机构(CA)对证书签名;
  • crt:由颁发证书机构(CA)签名后的证书,或者是开发者自签名的证书,包含证书持有人的信息,持有人的公钥,以及签署者的签名等信息;
  • pem:是基于Base64编码的证书格式,扩展名包括PEM、CRT和CER;

单向认证

服务端修改

package main

import (
	"service"

	"google.golang.org/grpc"

	"net"

	"log"

	"fmt"

	"google.golang.org/grpc/credentials"
)

func main() {
	fmt.Println("开始启动服务")

	// 添加证书
	creds, err0 := credentials.NewServerTLSFromFile("cert/server.pem", "cert/server.key")
	if err0 != nil {
		log.Fatal("证书生成失败", err0)
	}

    // 创建rpc实例(添加认证)
	rpcServer := grpc.NewServer(grpc.Creds(creds))

	// 服务注册
	service.RegisterProdServiceServer(rpcServer, service.ProductService)

	// 启动监听
	listener, err := net.Listen("tcp", ":8800")
	if err != nil {
		log.Fatal("启动监听失败", err)
	}

	// 启动服务
	err = rpcServer.Serve(listener)
	if err != nil {
		log.Fatal("启动服务失败", err)
	}

	fmt.Println("启动服务成功")
}

服务端启动

grpc介绍(二)——认证方式

客户端修改

package main

import (
	"google.golang.org/grpc"

	"log"

	"service"

	"context"

	"fmt"

	"google.golang.org/grpc/credentials"
)

func main() {
	// 添加公钥
	creds, err0 := credentials.NewClientTLSFromFile("../cert/server.pem", "*.dong.com")
	if err0 != nil {
		log.Fatal("证书错误: ", err0)
	}

	// 创建连接
	conn, err := grpc.Dial(":8800", grpc.WithTransportCredentials(creds))
	if err != nil {
		log.Fatal("服务端连接失败: ", err)
	}
    
    fmt.Println("证书认证通过")

	// 退出时关闭连接
	defer conn.Close()

	// 创建客户端实例
	productServiceClient := service.NewProdServiceClient(conn)

	// 方法请求
	resq, err := productServiceClient.GetProductStock(context.Background(), &service.ProductRequest{ProdId: 233})
	if err != nil {
		log.Fatal("调用gRPC方法失败: ", err)
	}

	fmt.Println("调用gRPC方法成功, ProdStock = ", resq.ProdStock)
}

客户端启动

grpc介绍(二)——认证方式

单向认证流程

grpc介绍(二)——认证方式

抓包分析

grpc介绍(二)——认证方式

工程框架

grpc介绍(二)——认证方式

双向认证

生成客户端公钥和私钥

# 生成私钥
openssl genpkey -algorithm RSA -out client.key

# 生成证书
openssl req -new -nodes -key client.key -out client.csr -days 3650 -config ./openssl.cnf -extensions v3_req

# 生成SAN证书
openssl x509 -req -days 365 -in client.csr -out client.pem -CA ca.crt -CAkey ca.key -CAcreateserial -extfile ./openssl.cnf -extensions v3_req

服务端修改

package main

import (
	"service"

	"google.golang.org/grpc"

	"net"

	"log"

	"fmt"

	"google.golang.org/grpc/credentials"

	"crypto/tls"

	"crypto/x509"

	"io/ioutil"
)

func main() {
	fmt.Println("开始启动服务")

	// 添加证书
	// creds, err0 := credentials.NewServerTLSFromFile("cert/server.pem", "cert/server.key")
	// if err0 != nil {
	// 	log.Fatal("证书生成失败", err0)
	// }

	// 证书认证-双向认证
	cert, err0 := tls.LoadX509KeyPair("cert/server.pem", "cert/server.key")
	if err0 != nil {
		log.Fatal("证书读取失败", err0)
	}

	fmt.Println("证书读取成功")

	// 创建一个新的、空的CertPool
	certPool := x509.NewCertPool()
	ca, err1 := ioutil.ReadFile("cert/ca.crt")
	if err1 != nil {
		log.Fatal("ca证书读取失败", err1)
	}

	fmt.Println("ca证书读取成功")

	// 尝试解析所传入的PEM编码的证书,如果解析成功会将其加到CertPool中,便于后面使用
	certPool.AppendCertsFromPEM(ca)
	// 构建基于TLS的TransportCredentials选项
	creds := credentials.NewTLS(&tls.Config{
		// 设置证书链, 允许包含一个或多个
		Certificates: []tls.Certificate{cert},
		// 要求必须校验客户端的证书
		ClientAuth: tls.RequireAndVerifyClientCert,
		// 设置根证书的集合, 校验方式使用ClientAuth中设定的模式
		ClientCAs: certPool,
	})

	fmt.Println("设置TLS的TransportCredentials选项成功")

	// 创建rpc实例
	rpcServer := grpc.NewServer(grpc.Creds(creds))

	// 服务注册
	service.RegisterProdServiceServer(rpcServer, service.ProductService)

	// 启动监听
	listener, err := net.Listen("tcp", ":8800")
	if err != nil {
		log.Fatal("启动监听失败", err)
	}

	// 启动服务
	err = rpcServer.Serve(listener)
	if err != nil {
		log.Fatal("启动服务失败", err)
	}

	fmt.Println("启动服务成功")
}

服务端启动

grpc介绍(二)——认证方式

客户端修改

package main

import (
	"google.golang.org/grpc"

	"log"

	"service"

	"context"

	"fmt"

	"google.golang.org/grpc/credentials"

	"crypto/tls"

	"crypto/x509"

	"io/ioutil"
)

func main() {
	// 添加公钥
	// creds, err0 := credentials.NewClientTLSFromFile("../cert/server.pem", "*.dong.com")
	// if err0 != nil {
	// 	log.Fatal("证书错误: ", err0)
	// }

	// 证书认证-双向认证
	// 从证书相关文件中读取解析信息, 得到证书公钥、密钥对
	cert, err0 := tls.LoadX509KeyPair("../cert/client.pem", "../cert/client.key")
	if err0 != nil {
		log.Fatal("证书读取失败", err0)
	}

	fmt.Println("证书读取成功")

	// 创建一个新的、空的CertPool
	certPool := x509.NewCertPool()
	ca, err1 := ioutil.ReadFile("../cert/ca.crt")
	if err1 != nil {
		log.Fatal("ca证书读取失败", err1)
	}

	fmt.Println("ca证书读取成功")

	// 尝试解析所传入的PEM编码的证书,如果解析成功会将其加到CertPool中,便于后面使用
	certPool.AppendCertsFromPEM(ca)
	// 构建基于TLS的TransportCredentials选项
	creds := credentials.NewTLS(&tls.Config{
		// 设置证书链, 允许包含一个或多个
		Certificates: []tls.Certificate{cert},
		ServerName:   "*.dong.com",
		RootCAs:      certPool,
	})

	fmt.Println("设置TLS的TransportCredentials选项成功")

	// 创建连接
	conn, err := grpc.Dial(":8800", grpc.WithTransportCredentials(creds))
	if err != nil {
		log.Fatal("服务端连接失败: ", err)
	}

	fmt.Println("证书认证通过")

	// 退出时关闭连接
	defer conn.Close()

	// 创建客户端实例
	productServiceClient := service.NewProdServiceClient(conn)

	// 方法请求
	resq, err := productServiceClient.GetProductStock(context.Background(), &service.ProductRequest{ProdId: 233})
	if err != nil {
		log.Fatal("调用gRPC方法失败: ", err)
	}

	fmt.Println("调用gRPC方法成功, ProdStock = ", resq.ProdStock)
}

客户端启动

grpc介绍(二)——认证方式

成功执行。

双向认证流程

grpc介绍(二)——认证方式

抓包分析

grpc介绍(二)——认证方式

工程框架

grpc介绍(二)——认证方式

Token认证

服务端修改

package main

import (
	"service"

	"google.golang.org/grpc"

	"net"

	"log"

	"fmt"

	"google.golang.org/grpc/credentials"

	"crypto/tls"

	"crypto/x509"

	"io/ioutil"

	"context"

	"google.golang.org/grpc/metadata"

	"google.golang.org/grpc/status"

	"google.golang.org/grpc/codes"
)

func main() {
	fmt.Println("开始启动服务")

	// 添加证书
	// creds, err0 := credentials.NewServerTLSFromFile("cert/server.pem", "cert/server.key")
	// if err0 != nil {
	// 	log.Fatal("证书生成失败", err0)
	// }

	// 证书认证-双向认证
	cert, err0 := tls.LoadX509KeyPair("cert/server.pem", "cert/server.key")
	if err0 != nil {
		log.Fatal("证书读取失败", err0)
	}

	fmt.Println("证书读取成功")

	// 创建一个新的、空的CertPool
	certPool := x509.NewCertPool()
	ca, err1 := ioutil.ReadFile("cert/ca.crt")
	if err1 != nil {
		log.Fatal("ca证书读取失败", err1)
	}

	fmt.Println("ca证书读取成功")

	// 尝试解析所传入的PEM编码的证书,如果解析成功会将其加到CertPool中,便于后面使用
	certPool.AppendCertsFromPEM(ca)
	// 构建基于TLS的TransportCredentials选项
	creds := credentials.NewTLS(&tls.Config{
		// 设置证书链, 允许包含一个或多个
		Certificates: []tls.Certificate{cert},
		// 要求必须校验客户端的证书
		ClientAuth: tls.RequireAndVerifyClientCert,
		// 设置根证书的集合, 校验方式使用ClientAuth中设定的模式
		ClientCAs: certPool,
	})

	fmt.Println("设置TLS的TransportCredentials选项成功")

	// token认证 -- 合法的用户名和密码
	var authInterceptor grpc.UnaryServerInterceptor
	authInterceptor = func(
		ctx context.Context,
		req interface{},
		info *grpc.UnaryServerInfo,
		handler grpc.UnaryHandler,
	) (resp interface{}, err error) {
		// 拦截请求, 验证token
		err = Auth(ctx)
		if err != nil {
			return
		}

		// 继续处理请求
		return handler(ctx, req)
	}

	// 创建rpc实例
	rpcServer := grpc.NewServer(grpc.Creds(creds), grpc.UnaryInterceptor(authInterceptor))

	// 服务注册
	service.RegisterProdServiceServer(rpcServer, service.ProductService)

	// 启动监听
	listener, err := net.Listen("tcp", ":8800")
	if err != nil {
		log.Fatal("启动监听失败", err)
	}

	// 启动服务
	err = rpcServer.Serve(listener)
	if err != nil {
		log.Fatal("启动服务失败", err)
	}

	fmt.Println("启动服务成功")
}

func Auth(ctx context.Context) error {
	md, ok := metadata.FromIncomingContext(ctx)
	if !ok {
		return fmt.Errorf("missing credentials")
	}

	var user string
	var passwd string

	if val, ok := md["user"]; ok {
		user = val[0]
	}

	if val, ok := md["passwd"]; ok {
		passwd = val[0]
	}

	if user != "admin" || passwd != "admin@123" {
		return status.Errorf(codes.Unauthenticated, "token认证失败")
	}

	fmt.Println("token认证成功")
	return nil
}

添加认证接口

// 新增auth.go文件

package auth

import "context"

type Authentication struct {
	User   string
	Passwd string
}

func (a *Authentication) GetRequestMetadata(context.Context, ...string) (
	map[string]string, error,
) {
	return map[string]string{"user": a.User, "passwd": a.Passwd}, nil
}

func (a *Authentication) RequireTransportSecurity() bool {
	return false
}

客户端修改

package main

import (
	"google.golang.org/grpc"

	"log"

	"service"

	"context"

	"fmt"

	"google.golang.org/grpc/credentials"

	"crypto/tls"

	"crypto/x509"

	"io/ioutil"

	"auth"
)

func main() {
	// 添加公钥
	// creds, err0 := credentials.NewClientTLSFromFile("../cert/server.pem", "*.dong.com")
	// if err0 != nil {
	// 	log.Fatal("证书错误: ", err0)
	// }

	// 证书认证-双向认证
	// 从证书相关文件中读取解析信息, 得到证书公钥、密钥对
	cert, err0 := tls.LoadX509KeyPair("../cert/client.pem", "../cert/client.key")
	if err0 != nil {
		log.Fatal("证书读取失败", err0)
	}

	fmt.Println("证书读取成功")

	// 创建一个新的、空的CertPool
	certPool := x509.NewCertPool()
	ca, err1 := ioutil.ReadFile("../cert/ca.crt")
	if err1 != nil {
		log.Fatal("ca证书读取失败", err1)
	}

	fmt.Println("ca证书读取成功")

	// 尝试解析所传入的PEM编码的证书,如果解析成功会将其加到CertPool中,便于后面使用
	certPool.AppendCertsFromPEM(ca)
	// 构建基于TLS的TransportCredentials选项
	creds := credentials.NewTLS(&tls.Config{
		// 设置证书链, 允许包含一个或多个
		Certificates: []tls.Certificate{cert},
		ServerName:   "*.dong.com",
		RootCAs:      certPool,
	})

	fmt.Println("设置TLS的TransportCredentials选项成功")

	token := &auth.Authentication{
		User:   "admin",
		Passwd: "admin@123",
	}

	// 创建连接
	conn, err := grpc.Dial(":8800", grpc.WithTransportCredentials(creds), grpc.WithPerRPCCredentials(token))
	if err != nil {
		log.Fatal("服务端连接失败: ", err)
	}

	fmt.Println("证书认证通过")

	// 退出时关闭连接
	defer conn.Close()

	// 创建客户端实例
	productServiceClient := service.NewProdServiceClient(conn)

	// 方法请求
	resq, err := productServiceClient.GetProductStock(context.Background(), &service.ProductRequest{ProdId: 233})
	if err != nil {
		log.Fatal("调用gRPC方法失败: ", err)
	}

	fmt.Println("调用gRPC方法成功, ProdStock = ", resq.ProdStock)
}

测试

1)先启动服务端,再启动服务端

服务端

grpc介绍(二)——认证方式

客户端

grpc介绍(二)——认证方式

token认证通过。

工程框架

grpc介绍(二)——认证方式

部分参考:

HTTPS协议:https://blog.csdn.net/qq_34827674/article/details/112589634

数字签名和数字证书:https://blog.csdn.net/qq_34827674/article/details/119081396

单向认证与双向认证:https://blog.csdn.net/qq_53267860/article/details/125045094文章来源地址https://www.toymoban.com/news/detail-422171.html

到了这里,关于grpc介绍(二)——认证方式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • .NetCore gRpc 客户端与服务端的单工通信Demo

    方式一 使用vs 2022(也可以是其他版本)创建一个grpc的服务,如下这样 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uipEG9Xu-1687172462785)(C:UsersAdministratorAppDataRoamingTyporatypora-user-imagesimage-20230619183828284.png)] 简单方便,创建项目后的目录结构如下图

    2024年02月09日
    浏览(53)
  • 在 C#和ASP.NET Core中创建 gRPC 客户端和服务器

    gRPC 是一种可以跨语言运行的现代高性能远程过程调用 (RPC) 框架。gRPC 实际上已经成为 RPC 框架的行业标准,Google 内外的组织都在使用它来从微服务到计算的“最后一英里”(移动、网络和物联网)的强大用例。 gRPC是一个高性能的开源的通用RPC框架,由Google公司开发,支持常

    2024年04月23日
    浏览(44)
  • Kubernetes客户端认证(二)—— 基于ServiceAccount的JWTToken认证

    在 Kubernetes 官方手册中给出了 “用户” 的概念,Kubernetes 集群中存在的用户包括 “普通用户” 与 “ServiceAccount”, 但是 Kubernetes 没有普通用户的管理方式,通常只是将使用集群根证书签署的有效证书的用户都被视为合法用户。 那么对于使得 Kubernetes 集群有一个真正的用户

    2023年04月11日
    浏览(98)
  • 基于grpc-java开发的普通工程在k8s内部署多实例,如何实现客户端流量的负载均衡

    本文主要讨论通过grpc-java开发的普通的java grpc工程,以多实例的方式部署在容器编排平台kubernetes(以下简称k8s)上,如何能够实现让同样部署在k8s 集群内的客户端请求流量均衡的分发到多个grpc应用部署实例上去。 grpc服务端程序在k8s内部署的多个实例通过headless service暴露服

    2024年01月17日
    浏览(47)
  • java案例-服务端与客户端(传输对象)

    SysUser 用户类 Operation 操作类 Client 客户端 Server 服务端 ServerReaderThread 服务端线程类 需要实现Serializable 方便序列化,传输对象 操作方法和被操作的用户 本例是一个 长连接 :一直挂在服务器端,那么服务器端的 读取线程中就必须要有一个while 循环 不断读取此长连接的内容

    2024年04月29日
    浏览(37)
  • DR.COM宽带认证客户端安装教程

    许多朋友下载了Dr.COM Client 宽带上网认证客户端不会安装使用,因为安装过程比较复杂,这也不能怪您不会哦!今天小编和大家分享一下安装教程。 DR.COM宽带认证客户端安装说明: 1. 首先要下载DR.COM宽带认证客户端,下载后双击Dr.COM安装程序,等待程序自动运行,选择安装语

    2024年02月06日
    浏览(57)
  • ESP32网络编程-TCP客户端数据传输

    本文将详细介绍在Arduino开发环境中,实现一个ESP32 TCP客户端,从而达到与TCP服务器数据交换的目标。 Internet 协议(IP)是 Internet 的地址系统,具有将数据包从源设备传递到目标设备的核心功能。IP 是建立网络连接的主要方式,奠定了 Internet 的基础。IP 不负责数据包排序或错

    2024年02月03日
    浏览(43)
  • Qt多线程TCP服务器客户端传输文件

    TCP是面向连接的运输层协议。应用程序在使用TCP协议之前,必须先建立TCP连接。在传送数据完毕后,必须释放已经建立的TCP连接。 每一条TCP连接只能有两个端点,每一条TCP连接只能是点对点的(一对一)。 TCP提供可靠交付的服务。通过TCP 连接传送的数据,无差错、不丢失、不

    2024年02月13日
    浏览(53)
  • Spring Security—OAuth2 客户端认证和授权

    关于 JWT Bearer 客户端认证的进一步详情,请参考OAuth 2.0客户端认证和授权许可的 JSON Web Token (JWT)简介。 JWT Bearer 客户端认证的默认实现是  NimbusJwtClientAuthenticationParametersConverter ,它是一个  Converter ,通过在  client_assertion  参数中添加签名的JSON Web Token(JWS)来定制令牌请求

    2024年02月08日
    浏览(51)
  • 【Kafka】Kafka客户端认证失败:Cluster authorization failed.

    kafka客户端是公司内部基于spring-kafka封装的 spring-boot版本:3.x spring-kafka版本:2.1.11.RELEASE 集群认证方式:SASL_PLAINTEXT/SCRAM-SHA-512 经过多年的经验,以及实际验证,配置是没问题的,但是业务方反馈用相同的配置,还是报错! 封装的kafka客户端版本过低,高版本的配置项:secu

    2024年01月17日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包