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

【gRPC-gateway】auth-通过拦截器从上下文中提取元数据用于认证,与从http header转发待认证数据到上下文进行验证,go案例

从grpc上下文中提取元数据用于认证 案例

interceptor.go

package serverimport ("context""errors""google.golang.org/grpc""google.golang.org/grpc/metadata""strings"
)// UnaryInterceptor 是一个 unary RPC 的拦截器,用于在处理请求前进行身份认证。
// 参数:
//
//	ctx - 上下文,用于传递请求相关的元数据。
//	req - 请求的数据。
//	info - 包含被拦截的 RPC 方法的信息。
//	handler - 下游的处理器,用于执行实际的 RPC 方法。
//
// 返回值:
//
//	响应数据和可能的错误。
func UnaryInterceptor(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) {// 在执行实际的处理函数前进行身份认证。err = auth(ctx)if err != nil {return nil, err}// 身份认证通过后,调用实际的处理函数。return handler(ctx, req)
}// StreamInterceptor 是一个 streaming RPC 的拦截器,用于在处理请求前进行身份认证。
// 参数:
//
//	srv - 服务器的实现。
//	ss - 服务器流,用于读取请求和写入响应。
//	info - 包含被拦截的 streaming RPC 方法的信息。
//	handler - 下游的处理器,用于执行实际的 streaming RPC 方法。
//
// 返回值:
//
//	可能的错误。
func StreamInterceptor(srv any, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {// 在执行实际的处理函数前进行身份认证。err := auth(ss.Context())if err != nil {return err}// 身份认证通过后,调用实际的处理函数。return handler(srv, ss)
}// auth 函数用于执行身份认证逻辑。
// 参数:
//
//	ctx - 上下文,用于传递请求相关的元数据。
//
// 返回值:
//
//	如果身份认证失败,返回错误;否则返回 nil。
func auth(ctx context.Context) error {// 从上下文中提取元数据,用于身份认证。md, ok := metadata.FromIncomingContext(ctx)if !ok {return errors.New("元数据获取失败,身份认证失败")}// 检查元数据中是否包含认证信息。authorization := md["authorization"]if len(authorization) < 1 {return errors.New("元数据获取失败,身份认证失败")}// 提取并验证 token。token := strings.TrimPrefix(authorization[0], "Bearer ")if token != bearerToken {return errors.New("身份认证失败")}// 身份认证成功。return nil
}// bearerToken 是用于身份认证的密钥。
var bearerToken = "asdfgh"

main.go

s := grpc.NewServer(grpc.UnaryInterceptor(server.UnaryInterceptor), grpc.StreamInterceptor(server.StreamInterceptor))

在这里插入图片描述


从http header转发到grpc上下文进行认证 案例

  • 因为gateway负责,将远端http请求转为gRPC从而与grpc服务器通信,所以应该在gateway中处理http header,使其中需要的部分放入grpc上下文中

在这里插入图片描述

通过在runtime.NewServeMux(inComingOpt)中添加处理函数inComingOpt可以解决

可以看到NewServeMux还支持很多操作
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/f7d775ef2dd74b6a9247e319cdeabda2.png
在这里插入图片描述

gateway.go

package gatewayimport ("context""flag""github.com/grpc-ecosystem/grpc-gateway/v2/runtime"gw "golang19-grpc-gateway/user/proto""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure""net/http"
)var (// grpc服务器端点grpcServerEndpoint = flag.String("grpc-server-endpoint", "localhost:50051", "gRPC server endpoint")
)// Run 启动一个 HTTP 服务器,用于将 HTTP 请求转发到 gRPC 服务器。
// 该函数配置了一个 HTTP 多路复用器以处理不同的 HTTP 路径,并将这些路径与 gRPC 方法关联起来。
// 它还设置了一个不安全的 gRPC 连接选项,仅适用于开发环境。
// 返回值: 如果 HTTP 服务器启动失败或在处理请求时遇到错误,则返回错误。
func Run() error {// 初始化一个上下文对象,用于取消操作和传递请求范围的值。ctx := context.Background()// 创建一个可取消的上下文,以便在函数退出时取消可能的挂起操作。ctx, cancel := context.WithCancel(ctx)// 确保在函数退出时取消上下文。defer cancel()// inComingOpt 配置了一个处理传入的http请求头的选项// 该选项使用一个函数来检查和转换请求头的键// 该匹配器函数决定哪些传入的HTTP头应该被传递给gRPC上下文,以及是否应该修改这些头的键。inComingOpt := runtime.WithIncomingHeaderMatcher(func(s string) (string, bool) {// 如果matcher返回true,则该标头将传递给gRPC上下文。要在传递给gRPC上下文之前转换标头,匹配器应返回修改后的标头。switch s {// 对于"Service-Authorization"头,将其转换为"service-authorization"并传递给gRPC上下文。case "Service-Authorization":return "authorization", true// 不修改请求头的键,不传递给上下文default:return "", false}})// 创建一个 HTTP 处理多路复用器,用于将 HTTP 请求分发到不同的处理程序。mux := runtime.NewServeMux(inComingOpt)// 为 "/upload" 路径添加一个处理程序,处理 POST 请求。mux.HandlePath("POST", "/upload", uploadHandler)// 配置一个不安全的 gRPC 连接选项,这仅适用于开发环境。opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}// 将 gRPC 方法映射为 HTTP 请求,使 HTTP 客户端可以与 gRPC 服务器通信。err := gw.RegisterUserHandlerFromEndpoint(ctx, mux, *grpcServerEndpoint, opts)// 如果注册处理程序时发生错误,返回该错误。if err != nil {return err}// 启动 HTTP 服务器,监听端口 8081,使用配置好的多路复用器处理请求。return http.ListenAndServe(":8081", mux)
}

这样改造后,无论是验证上下文中指定数据,还是验证请求头中的数据,只需要保持提取后,重新指定的待验证的key相同就可同时实现
在这里插入图片描述

结果演示

既可以验证authorization
在这里插入图片描述


也可以验证headers
在这里插入图片描述


https://github.com/0voice

http://www.lryc.cn/news/536489.html

相关文章:

  • Sass基础知识以及常用知识整理
  • Redis 内存回收机制
  • docker安装mongo,导入、导出数据
  • Excel常用操作
  • 嵌入式EasyRTC实时通话支持海思hi3516cv610,编译器arm-v01c02-linux-musleabi-gcc
  • 在freertos中,中断优先级和任务优先级之间的关系和使用方法
  • 设置ollama接口能外部访问
  • Go GUI 框架, energy many-browser 示例解读
  • Docker 部署 MongoDB | 国内阿里镜像
  • 软件工程-软件设计
  • Elasticsearch:15 年来致力于索引一切,找到重要内容
  • DeepSeek大模型一键部署解决方案:全平台多机分布式推理与国产硬件优化异构计算私有部署
  • Docker 部署 MySQL-5.7 单机版
  • 打破AI黑盒,拥抱开源力量:基于openGauss+DeepSeek的本地知识库,打造你的专属AI助手!
  • java配置api,vue网页调用api从oracle数据库读取数据
  • visual studio导入cmake项目后打开无法删除和回车
  • linux运行kettle 遇到问题汇总
  • 初识camel智能体(一)
  • 如何在Excel和WPS中进行翻译
  • TCP的拥塞控制
  • 【前端】几种常见的跨域解决方案代理的概念
  • C++之2048小游戏 第二期
  • Redis7——基础篇(一)
  • day9手机创意软件
  • C# Dictionary的实现原理
  • 学习笔记-人脸识别相关编程基础
  • BUU37 [DASCTF X GFCTF 2024|四月开启第一局]web1234【代码审计/序列化/RCE】
  • (五)Spring Boot学习——spring security +jwt使用(前后端分离模式)
  • Java中使用EasyExcel
  • 前沿科技改变生活新趋势