Golang——gRPC认证

一. OpenSSL

        1.1 介绍

        OpenSSL是一个开放源代码的软件库包,用于支持网络通讯过程中的加密。这个库提供的功能包含了SSL和TLS协议的实现,并可用于生成密钥、证书、进行密码运算等。

        其组成主要包括一下三个组件:

  1. openssl:多用途的命令行工具

  2. libcrypto:加密算法库

  3. libssl:加密模块应用库,实现了ssl及tls

openssl可以实现秘钥证书管理、对称加密和非对称加密 。

        官网:[ Downloads ] - /source/index.html

        1.2 Windows安装方法

        OpenSSL官网没有提供windows版本的安装包,可以选择其它开源平台提供的工具。

Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions

        以该工具为例:

        进入下载界面,选择下载的版本,下载完,之后安装即可。

        1.3 生成公钥和私钥

        openssl命令详解-CSDN博客

生成私钥:openssl genrsa -out rsa_private_key.pem 1024
生成公钥:openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem

二. gRPC认证

        gRPC默认内置了两种认证方式:

  • SSL/TLS认证
  • 基于Token的认证

        同时,gRPC提供了接口用于扩展自定义认证方式。

        2.1 TLS认证

        2.1.1 什么是TLS认证

        TLS(Transport Layer Security,安全传输层),TLS是建立在传输层TCP协议之上的协议,服务于应用层,它的前身是SSL(Secure Socket Layer,安全套接字层),它实现了将应用层的报文进行加密后再交由TCP进行传输的功能。

        2.1.2 TLS的作用

TLS协议主要解决如下三个网络安全问题。

  • 保密(message privacy),保密通过加密encryption实现,所有信息都加密传输,第三方无法嗅探;
  • 完整性(message integrity),通过MAC校验机制,一旦被篡改,通信双方会立刻发现;
  • 认证(mutual authentication),双方认证,双方都可以配备证书,防止身份被冒充;

        2.1.3 TLS认证实例

  • 证书制作

        制作公钥:自签名公钥(x509),   制作私钥。

#生成一个名为server_private.key的RSA私钥,使用SHA256算法和4096位密钥长度。然后使用该私钥生成一个有效期为36500天的自签名证书,并将其保存为名为server.pem的文件。同时在证书中添加subjectAltName扩展,指定DNS名称为www.wy.com。
openssl req -newkey rsa:4096 -nodes -sha256 -keyout server_private.key -x509 -days 36500 -out server.pem -addext "subjectAltName =DNS:www.wy.com"
  •  openssl req:生成自签名证书
  • -newkey rsa:4096 :生成新的4096位rsa密钥对
  • -sha256:使用sha256加密
  • -keyout:指定生成的私钥文件
  • -x509:指输出证书
  • -days 36500:有效期 36500
  • -out:输出证书的文件名
  • -addext:添加扩展

        注意需要在证书中添加subjectAltName扩展,指定DNS名称。不然在客户端连接服务器时会报错,报错信息为:

        rpc error: code = Unavailable desc = connection error: desc = "transport: authentication handshake failed: tls: failed to verify certificate: x509: certificate relies on legacy Common Name field, use SANs instead"

        因为go1.15 版本开始废弃CommonName,因此推荐使用SAN证书。如果想兼容之前的方式,需要设置环境变量 GODEBUG为 x509ignoreCN=0。(创建 SSL/TLS 证书时,证书依赖于传统的 Common Name (CN) 字段,而没有使用现代标准所推荐的 Subject Alternative Names (SANs) 字段。现代的 TLS 客户端(比如最新版本的浏览器和安全工具)要求证书使用 SANs 字段来指定有效的主机名。)

        自定义信息: 

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) [AU]:CN #国家
State or Province Name (full name) [Some-State]:SHANGHAI #省份
Locality Name (eg, city) []:SHANGHAI #城市
Organization Name (eg, company) [Internet Widgits Pty Ltd]:BF #公司
Organizational Unit Name (eg, section) []:Dev #部门
Common Name (e.g. server FQDN or YOUR name) []:www.wy.com #服务器名称
Email Address []:xxx@xxx.com #邮箱地址
  • 目录结构

  • 示例代码 

         服务端代码:

package mainimport ("context""fmt""net"hello "sample-app/grpc/proto""google.golang.org/grpc""google.golang.org/grpc/credentials" //引入gRPC认证包
)const (//服务器地址Addr = "127.0.0.1:8080"
)type helloService struct{}//定义hello 服务
var HelloService = helloService{}//实现proto hello service方法
func (h helloService) SayHello(c context.Context, req *hello.HelloRequest) (*hello.HelloResponse, error) {resp := new(hello.HelloResponse)resp.Message = fmt.Sprintf("Hello %s", req.Name)return resp, nil
}func main() {ls, err := net.Listen("tcp", Addr)if err != nil {fmt.Println(err)return}//TLS认证cert, err := credentials.NewServerTLSFromFile("..\\..\\key\\server.pem", "..\\..\\key\\server_private.key")if err != nil {fmt.Println(err)return}//新建一个grpc服务器,并开启TLS认证//上面监听并没有进行连接客户端server := grpc.NewServer(grpc.Creds(cert))//注册HelloServicehello.RegisterHelloServer(server, HelloService)fmt.Println("Listen on" + Addr + "with TLS")//这里面才会连接客户端,需要进行认证server.Serve(ls)
}
  • credentials.NewServerTLSFromFile:从输入证书文件和密钥文件为服务端构造TLS凭证

  • grpc.Creds:返回一个ServerOption,用于设置服务器连接的凭证。

        客户端代码:

package mainimport ("context""fmt"hello "sample-app/grpc/proto""google.golang.org/grpc""google.golang.org/grpc/credentials"
)const (、//gRPC服务器地址Addr = "127.0.0.1:8080"
)func main() {//TLS连接cert, err := credentials.NewClientTLSFromFile("..\\..\\key\\server.pem", "www.wy.com")if err != nil {fmt.Println("credentials fail ", err)return}//请求连接的时候 需要认证conn, err := grpc.Dial(Addr, grpc.WithTransportCredentials(cert))if err != nil {fmt.Println("Dial fail", err)return}defer conn.Close()c := hello.NewHelloClient(conn)req := new(hello.HelloRequest)req.Name = "gRPC"resp, err := c.SayHello(context.Background(), req)if err != nil {fmt.Println("say hello fail", err)return}fmt.Println(resp.Message)
}
  • credentials.NewClientTLSFromFile:从输入的证书文件中为客户端构造TLS凭证。

  • grpc.WithTransportCredentials:配置连接级别的安全凭证(例如,TLS/SSL),返回一个DialOption,用于连接服务器。

        proto文件:

syntax="proto3";
package hello;
option go_package="hello";service Hello
{rpc SayHello(HelloRequest)returns(HelloResponse){}; 
}message HelloRequest
{string name = 1;
}message HelloResponse
{string message = 1;
}

使用下面命令生成pb.go文件:

protoc --go_out=plugins=grpc:"生成pb.go文件地址" -I="proto文件地址" "proto文件地址\文件" 

演示:

        实际TLS认证不是这样,客户端和服务器时分离的。客户端有证书(包含公钥),服务端有证书和私钥。

        客户端发送请求给服务器请求连接,服务器将证书通过私钥加密后发送给客户端。客户端有证书,里面包含服务器私钥对应的公钥。使用公钥对数据进行解密,获得证书数据,与本地证书数据进行比较。

         2.2 Token认证

        继续扩展上面的代码,实现TLS+Token认证机制。

        2.2.1 什么是Token认证

        Token认证是一种基于Token的身份验证方法,用于在客户端和服务器之间进行身份验证。以下是Token认证的主要概念、流程以及优缺点:

  • 主要概念

    • Token的含义:Token(令牌)是服务端生成的一串字符串,作为客户端进行请求的一个标识。
    • Token的组成:一般包括用户身份标识(uid)、时间戳(time)和签名(sign)等元素。
    • Token的作用:Token主要用于身份验证、授权、会话管理和跨域资源共享(CORS)等方面。
  • 认证流程

    • 用户登录并获取Token:用户使用用户名和密码登录,成功后服务端生成Token并发送给客户端。
    • 客户端存储和使用Token:客户端将Token保存在本地(如cookie或localStorage),并在后续请求中携带该Token。
    • 服务端验证Token:服务端收到请求后,验证Token的合法性,若合法则处理请求并返回数据。

        2.2.2 示例代码

        根据上面的代码,实现TLS+Token认证机制。

  • 认证原理

        客户端发送请求,会将Token放到context.Context上下文中,服务器收到请求,从上下文中获取Token验证,然后进行下一步操作。

  • 目录结构

  • 客户端代码

        grpc/credential包内默认定义了PerRPCCredentials接口,是提供用于自定义接口,他的作用是将所需安全认证信息添加到每个RPC上下文中。其包含两个方法。

type PerRPCCredentials interface {//获取当前请求认证所需的元数据GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error)//是否需要基于TLS认证进行安全传输RequireTransportSecurity() bool
}
package mainimport ("context""fmt"hello "sample-app/grpc/proto""google.golang.org/grpc""google.golang.org/grpc/credentials"
)const (Addr = "127.0.0.1:8080"//是否使用TLSOpenTLS = true
)// 自定义认证
type Token struct {Appid  stringAppkey string
}// 实现自定义认证方法
func (t Token) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {return map[string]string{"appid":  t.Appid,"appkey": t.Appkey,}, nil
}// 实现自定义认证是否开启TLS
func (t Token) RequireTransportSecurity() bool {return OpenTLS
}func main() {//TLS连接var opt []grpc.DialOptionif OpenTLS {cert, err := credentials.NewClientTLSFromFile("..\\..\\key\\server.pem", "www.wy.com")if err != nil {fmt.Println("credentials fail ", err)return}opt = append(opt, grpc.WithTransportCredentials(cert))} else {opt = append(opt, grpc.WithInsecure())}//使用自定义认证tk := Token{Appid:  "101010",Appkey: "i am a key",}opt = append(opt, grpc.WithPerRPCCredentials(&tk))conn, err := grpc.Dial(Addr, opt...)if err != nil {fmt.Println("Dial fail", err)return}defer conn.Close()//初始化服务器c := hello.NewHelloClient(conn)req := new(hello.HelloRequest)req.Name = "gRPC"resp, err := c.SayHello(context.Background(), req)if err != nil {fmt.Println("say hello fail", err)return}fmt.Println(resp.Message)
}

        定义一个结构Token,包含Token所需属性字段。实现PerRPCCredentials接口的两个方法。每次调用token信息会通过请求metadata传输到服务端。

        下面查看服务端如何获取metadata中信息。 

  • 服务端代码

        使用metadata.FromIncomingContext:从上下文中获取元数据。

package mainimport ("context""fmt""net"hello "sample-app/grpc/proto""google.golang.org/grpc""google.golang.org/grpc/codes""google.golang.org/grpc/credentials" //引入gRPC认证包"google.golang.org/grpc/metadata"
)var Addr = "127.0.0.1:8080"type helloService struct{}var HelloService = helloService{}func (h helloService) SayHello(c context.Context, req *hello.HelloRequest) (*hello.HelloResponse, error) {//认证md, ok := metadata.FromIncomingContext(c)if !ok {return nil, grpc.Errorf(codes.Unauthenticated, "无Token认证信息")}var appid stringvar appkey stringvals := md.Get("appid")if len(vals) != 0 {appid = vals[0]}val_key := md.Get("appkey")if len(val_key) != 0 {appkey = val_key[0]}//认证tokenif appid != "101010" || appkey != "i am a key" {return nil, grpc.Errorf(codes.Unauthenticated, "Token认证信息错误: Appid:%s, Appkey:%s", appid, appkey)}//fmt.Println("authenticated succ " + appid + "-" + appkey)resp := new(hello.HelloResponse)resp.Message = fmt.Sprintf("Hello %s \nToken info: Appid=%s, AppKey=%s", req.Name, appid, appkey)return resp, nil
}func main() {ls, err := net.Listen("tcp", Addr)if err != nil {fmt.Println(err)return}//TLS认证cert, err := credentials.NewServerTLSFromFile("..\\..\\key\\server.pem", "..\\..\\key\\server_private.key")if err != nil {fmt.Println(err)return}//新建一个grpc服务器,并开启TLS认证server := grpc.NewServer(grpc.Creds(cert))//注册HelloServicehello.RegisterHelloServer(server, HelloService)fmt.Println("Listen on " + Addr + " with TLS")server.Serve(ls)
}
  • 演示 

        成功: 

         失败:

        补充:

        google.golang.org/grpc/credentials/oauth 包已实现了用于 Google API oauth jwt 验证
的方法,使用方法可以参考 官方文档 。在实际应用中,我们可以根据自己的业务需求实现合适的验证方 式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/347457.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MTK烧录USB驱动下载

下载链接 https://www.catalog.update.microsoft.com/Search.aspx?qMediaTek%20USB%20Port 驱动安装教程 https://miuiver.com/install-official-mediatek-driver/

@Test注解方法,方法无法执行

1.背景 写了一个测试方法,执行后如图 2.原因是 该项目是springbootgradle...构建的项目 在build.gradle配置文件中关闭了单元测试: test {useJUnitPlatform()// 是否启用单元测试enabled false } 3.处理方式 开启单元测试 test {useJUnitPlatform()// 是否启用单元测试ena…

操作系统复习-Linux的文件系统

文件系统概述 FAT FAT(File Allocation Table)FAT16、FAT32等,微软Dos/Windows使用的文件系统使用一张表保存盘块的信息 NTFS NTFS (New Technology File System)WindowsNT环境的文件系统NTFS对FAT进行了改进,取代了日的文件系统 EXT EXT(Extended…

全域推广是什么意思?业务范围有哪些?

随着全域时代的到来,与全域相关的各种概念不断涌现,引发了一轮又一轮的热议。在此背景下,全域推广一经出现便一跃成为了互联网的有一大热词,以全域推广是什么意思为代表的相关问题也成为了多个创业者社群中的热点话题。 相关资料显…

Linux基础(2)基础命令与vim

文件的复制和移动 cp 拷贝文件和目录 cp file file_copy --> file 是目标文件,file_copy 是拷贝出来的文件 cp file one --> 把 file 文件拷贝到 one 目录下,并且文件名依然为 file cp file one/file_copy --> 把 file 文件拷贝到 one 目录下…

MCK主机加固:智能科技,构筑网络安全的铜墙铁壁

在数字化转型的浪潮中,企业服务器的安全已成为维护业务连续性和保护数据资产的关键。MCK主机加固产品,以其创新技术,为企业提供了一个全面、智能、高效的安全解决方案。 一、智能安全监测 MCK主机加固产品采用深度学习算法,能够…

SpringCloud-OpenFeign拓展-连接池、最佳使用方法、日志输出

目录 1 OpenFeign连接池 1.1 常见连接类型 1.2 连接池使用方法 1.2.1 引入依赖 1.2.2 开启连接池功能 1.2.3 配置完成,重启实例即可,底层将更改设置。 2 OpenFeign最佳使用方法 2.1 每个微服务都是单独的project,内部有三个独立模块 …

C# Web控件与数据感应之模板循环输出

目录 关于模板循环输出 准备数据源 ​范例运行环境 RepeatHtml 方法 设计与实现 如何获取模板内容 getOuterHtml 方法 getInnerHtml 方法 调用示例 小结 关于模板循环输出 数据感应也即数据捆绑,是一种动态的,Web控件与数据源之间的交互&…

测试开发面经分享,面试七天速成 DAY 1

1. get、post、put、delete的区别 a. get请求: i. 用于从服务器获取资源。请求参数附加在URL的查询字符串中。 ii. 对服务器的请求是幂等的,即多次相同的GET请求应该返回相同的结果。 iii. 可以被缓存,可以被收藏为书签。 iv. 对于敏感数据不…

vscode打包vue项目

1)npm install 2)npm install -g vue/cli 3)npm run build 第三步注意:要查看根目录下 package.json 配置; 如果和我的一样 3)应该为 npm run build:prod 4)将dist 文件考到nginx等web服务器即可使用…

Go方法特性详解:简单性和高效性的充分体现

本文深入探讨了Go语言中方法的各个方面,包括基础概念、定义与声明、特性、实战应用以及性能考量。文章充满技术深度,通过实例和代码演示,力图帮助读者全面理解Go方法的设计哲学和最佳实践。 关注作者,分享互联网架构、云服务技术的…

Angular封装高德地图组件实现输入框搜索,地图点击选地点

Angular封装高德地图组件实现输入框搜索,地图点击选地点(Angular17版本) 话不多说直接上代码 创建一个独立组件 html代码: <div style"position: relative;"><input #searchInput nz-input placeholder"请输入地址"/><div #mapContaine…

如何快速上手Python,成为一名数据分析师

如何快速上手Python&#xff0c;成为一名数据分析师 成为一名数据分析师需要掌握Python编程语言以及数据分析相关的知识和技能。以下是一些步骤和建议&#xff0c;帮助你快速上手Python并成为一名数据分析师&#xff1a; 学习Python基础知识&#xff1a;首先&#xff0c;你需要…

机器学习-聚类算法

1.有监督学习与无监督学习 有监督&#xff1a;在训练集中给的数据中有X和Y&#xff0c;根据这些数据训练出一组参数对预测集进行预测 无监督&#xff1a;在训练集中给的数据只有X没有Y&#xff0c;根据X数据找相似度参数来对预测集进行预测 2.数据间的相似度 2.1距离相似度…

前端 Web 与原生应用端 WebView 通信交互 - HarmonyOS Next

基于鸿蒙 HarmonyOS Next 与前端 Vue 通信交互相关小结; DevEco Studio NEXT Developer Preview2 Vue js 两端相互拟定好协议后,通过前端页面的点击事件,将所需的数据传输给原生移动端组件方法中,处理后将消息回传至前端. 根据官方文档的案例尝试,但没成功 ... 后经过几经尝试…

随笔——预处理详解

目录 前言预定义符号#define#define定义常量#define定义宏 带有副作用的宏参数宏替换的规则宏和函数的对比#和###运算符##运算符 命名约定#undef命令行定义条件编译头文件的包含包含方式嵌套包含 其他预处理指令完 前言 之前我们在《随笔——编译与链接》中对预处理作了大致的…

【ARM Cache 及 MMU 系列文章 6 -- Cache 寄存器 CTR_EL0 | CLIDR | CCSIDR | CSSELR 使用详解 1】

请阅读【ARM Cache 及 MMU/MPU 系列文章专栏导读】 及【嵌入式开发学习必备专栏】 文章目录 Cache 常用寄存器Cache CSSELR 寄存器Cache CSSELR 使用场景Cache CSSELR 操作示例 Cache CLIDR 寄存器LoUU 介绍LoUU 使用 LoUIS 介绍CLIDR 使用 Cache CCSIDR 寄存器Cache CTR_EL0 C…

中科数安 |-公司办公透明加密系统,数据防泄漏软件

#数据防泄漏软件# 中科数安是一家专注于提供企业级数据防泄漏解决方案的公司&#xff0c;其办公透明加密系统是专为保护企业内部核心数据资料设计的。 PC地址&#xff1a;——www.weaem.com 该系统通过以下主要功能模块实现高效的安全防护&#xff1a; 文档透明加密&#xff1…

滴滴出行 大数据研发实习生【继任】

大数据研发实习生JD 职位描述 1、负责滴滴核心业务的数据建设&#xff0c;设计并打造适应滴滴一站式出行平台业务特点的数仓体系。 2、负责抽象核心业务流程&#xff0c;沉淀业务通用分析框架&#xff0c;开发数仓中间层和数据应用产品。 3、负责不断完善数据治理体系&#xff…

【数据结构】栈的应用

目录 0 引言 1 栈在括号匹配中的应用 2 栈在表达式求值中的应用 2.1 算数表达式 2.2 中缀表达式转后缀表达式 2.3 后缀表达式求值 3 栈在递归中的应用 3.1 栈在函数调用中的作用 3.2 栈在函数调用中的工作原理 4 总结 0 引言 栈&#xff08;Stack&#xff09;是一…