在 gRPC 中使用 JWT(JSON Web Tokens)进行身份验证是一种常见的做法,它可以帮助你确保请求方的身份和权限。下面是一种使用 gRPC 和 JWT 进行身份验证的步骤:

  1. 生成和签发 JWT: 在用户登录成功后,你需要生成一个 JWT 并将其签发给用户。JWT 中可以包含一些有关用户身份、角色、权限等的信息。
  2. 在 gRPC 的上下文中传递 JWT: 当客户端发送 gRPC 请求时,可以将 JWT 放置在 gRPC 请求的元数据(Metadata)中,作为请求的一部分。这样,服务器端就可以获取 JWT 并对其进行验证。
  3. 服务器端验证 JWT: 在 gRPC 服务端,你需要编写代码来验证接收到的 JWT。这通常涉及到验证 JWT 的签名是否有效,以及检查其中的身份信息和权限等。
  4. 决策和授权: 根据验证后的 JWT 信息,你可以决定是否允许用户继续访问请求的资源。这可能涉及到一些授权策略和业务逻辑。

以下是一个简单的示例,展示如何在 gRPC 中使用 JWT 进行身份验证:

proto文件

内容如下:

syntax = "proto3";

package chaincode.pb;

option go_package = "./;pb";

message HelloRequest { string name = 1; }
message HelloResponse { string reply = 2; } service SayHi { rpc Hi(HelloRequest) returns (HelloResponse); }

通过下面的命令生成相关的文件:

$ protoc --go_out=./ --go-grpc_out=./ example.proto
$ tree
.
├── example_grpc.pb.go
├── example.pb.go
└── example.proto 0 directories, 3 files

server端

跟 client 端约定内容如下:

  • token有效期为半小时
  • iss使用gRPC token
  • sub使用gRPC example server

代码如下:

package main

import (
"chaincode/pb"
"context"
"fmt"
"net"
"time" "github.com/golang-jwt/jwt/v5"
"github.com/pkg/errors"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
) var testKey = "testKey" type HiService struct {
pb.UnimplementedSayHiServer
} func verifyToken(tokenString string) error {
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
return []byte(testKey), nil
})
if err != nil {
return errors.Wrap(err, "init token parser error")
}
if !token.Valid {
return errors.New("invalid token")
}
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
return errors.New("invalid claims")
}
exp, err := claims.GetExpirationTime()
if err != nil {
return errors.Wrap(err, "GetExpirationTime from token error")
} now := time.Now()
if now.Sub(exp.Time) > 0 {
return errors.New("the token expires")
}
if claims["sub"] != "gRPC example server" {
return errors.New("invalid sub")
}
if claims["iss"] != "gRPC token" {
return errors.New("invalid iss")
}
return nil
} func (s *HiService) Hi(ctx context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) { md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, errors.New("token信息获取失败")
}
token := md.Get("Authorization")[0]
if err := verifyToken(token); err != nil {
return nil, errors.Wrap(err, "token验证失败")
} return &pb.HelloResponse{Reply: "hello " + req.Name}, nil
} func main() {
// 创建grpc服务示例
sv := grpc.NewServer()
// 注册我们的服务
pb.RegisterSayHiServer(sv, new(HiService)) // 绑定端口,提供服务
lis, err := net.Listen("tcp", ":50001")
if err != nil {
panic(err)
}
// 启动服务
fmt.Println("liston on: 50001")
sv.Serve(lis)
}
$ go run main.go
liston on: 50001

client

代码如下:

package main

import (
"chaincode/pb"
"context"
"fmt"
"time" "github.com/golang-jwt/jwt/v5"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
) var testKey = "testKey" func genToken() (string, error) {
claims := jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)),
Issuer: "gRPC token",
Subject: "gRPC example client",
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString([]byte(testKey))
} type TokeAuth struct {
Token string
} func (t *TokeAuth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
return map[string]string{
"Authorization": t.Token,
}, nil
} func (t *TokeAuth) RequireTransportSecurity() bool {
return false
} func main() {
token, err := genToken()
if err != nil {
panic(err)
}
conn, err := grpc.Dial("localhost:50001", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithPerRPCCredentials(&TokeAuth{Token: token}))
if err != nil {
panic(err)
}
defer conn.Close() client := pb.NewSayHiClient(conn) resp, err := client.Hi(context.Background(), &pb.HelloRequest{Name: "Wang"})
if err != nil {
panic(err)
}
fmt.Println(resp.String())
}

现在我们先将 client 端生成 token 的sub 设置为 gRPC example client,执行

$ go run main.go
panic: rpc error: code = Unknown desc = token验证失败: invalid sub goroutine 1 [running]:
main.main()
/root/go/src/example/client/main.go:55 +0x2f2
exit status 2

再将 client 端生成 token 的sub 设置为 gRPC example server,执行

$ go run main.go
reply:"hello Wang"

以上示例是一个简单的代码示例,实际上还需要处理错误、安全性和其他细节。


声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。

Author: mengbin

blog: mengbin

Github: mengbin92

cnblogs: 恋水无意


gRPC with JWT的更多相关文章

  1. Akka-CQRS(16)- gRPC用JWT进行权限管理

    前面谈过gRPC的SSL/TLS安全机制,发现设置过程比较复杂:比如证书签名:需要服务端.客户端两头都设置等.想想实际上用JWT会更加便捷,而且更安全和功能强大,因为除JWT的加密签名之外还可以把私密 ...

  2. gRPC四种模式、认证和授权实战演示,必赞~~~

    前言 上一篇对gRPC进行简单介绍,并通过示例体验了一下开发过程.接下来说说实际开发常用功能,如:gRPC的四种模式.gRPC集成JWT做认证和授权等. 正文 1. gRPC四种模式服务 以下案例演示 ...

  3. 编写一个go gRPC的服务

    前置条件: 获取 gRPC-go 源码 $ go get google.golang.org/grpc 简单例子的源码位置: $ cd $GOPATH/src/google.golang.org/gr ...

  4. grpc编译错误解决

    berli@berli-VirtualBox:~/grpc$ make [MAKE]    Generating cache.mk [C]       Compiling src/core/lib/s ...

  5. ASP.NET Core 3.0 gRPC 身份认证和授权

    一.开头聊骚 本文算是对于 ASP.NET Core 3.0 gRPC 研究性学习的最后一篇了,以后在实际使用中,可能会发一些经验之文.本文主要讲 ASP.NET Core 本身的认证授权和gRPC接 ...

  6. gRPC asp.net core自定义策略认证

    在GitHub上有个项目,本来是作为自己研究学习.net core的Demo,没想到很多同学在看,还给了很多星,所以觉得应该升成3.0,整理一下,写成博分享给学习.net core的同学们. 项目名称 ...

  7. 浅议Grpc传输机制和WCF中的回调机制的代码迁移

    浅议Grpc传输机制和WCF中的回调机制的代码迁移 一.引子 如您所知,gRPC是目前比较常见的rpc框架,可以方便的作为服务与服务之间的通信基础设施,为构建微服务体系提供非常强有力的支持. 而基于. ...

  8. Go gRPC进阶-go-grpc-middleware使用(八)

    前言 上篇介绍了gRPC中TLS认证和自定义方法认证,最后还简单介绍了gRPC拦截器的使用.gRPC自身只能设置一个拦截器,所有逻辑都写一起会比较乱.本篇简单介绍go-grpc-middleware的 ...

  9. akka-grpc - 基于akka-http和akka-streams的scala gRPC开发工具

    关于grpc,在前面的scalaPB讨论里已经做了详细的介绍:google gRPC是一种全新的RPC框架,在开源前一直是google内部使用的集成工具.gRPC支持通过http/2实现protobu ...

  10. 跟我一起学Go系列:Go gRPC 安全认证方式-Token和自定义认证

    Go gRPC 系列: 跟我一起学Go系列:gRPC安全认证机制-SSL/TLS认证 跟我一起学 Go 系列:gRPC 拦截器使用 跟我一起学 Go 系列:gRPC 入门必备 接上一篇继续讲 gRPC ...

随机推荐

  1. Mac 安装 cnpm

    npm set registry https://registry.npm.taobao.org npm set disturl https://npm.taobao.org/dist npm cac ...

  2. python 正则表达式简单使用

    定义: 正则表达式,又称规则表达式,通常被用来检索.替换那些符合某个模式(规则)的文本. 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符.及这些特定字符的组合,组成一个&quo ...

  3. xv6book阅读 chapter2

    一个操作系统至少应该满足三个需求:多路复用.隔离.交互.本章主要介绍如何组织操作系统来实现以上的三个需求,本文关注的是一种围绕单核进行设计的方法,这种设计是被许多uinx操作系统所使用的.Xv6运行在 ...

  4. CVPR2022 前沿研究成果解读:基于生成对抗网络的深度感知人脸重演算法

    凭借在人脸生成领域的扎实积累和前沿创新,阿里云视频云与香港科技大学合作的最新研究成果<基于生成对抗网络的深度感知人脸重演算法 >(Depth-Aware Generative Advers ...

  5. 路径规划之 A* 算法

    算法介绍 A*(念做:A Star)算法是一种很常用的路径查找和图形遍历算法.它有较好的性能和准确度.本文在讲解算法的同时也会提供Python语言的代码实现,并会借助matplotlib库动态的展示算 ...

  6. 森林消防智慧预警:火灾监测 Web GIS 可视化平台

    前言 森林火灾是一种突发性强.破坏性大.处置救助较为困难的自然灾害.2021 年前三季度全国共发生森林火灾 527 起,受害森林面积约 2628 公顷,15 人死亡:发生草原火灾 12 起,受害草原面 ...

  7. vue prop 会接收不同的数据类型

    refAge: { type: Number, default: 0 }, refName: { type: String, default: '' }, hotDataLoading: { type ...

  8. spring--Bean的作用域及应用场景

    这六种Spring Bean的作用域适用于不同的应用场景: Singleton: 在Spring IoC容器中仅存在一个Bean实例,Bean以单例方式存在.无论我们是否在配置文件中显式定义,所有的S ...

  9. spring启动流程 (1) 流程概览

    本文将通过阅读AnnotationConfigApplicationContext源码,分析Spring启动流程. 创建AnnotationConfigApplicationContext Annot ...

  10. C++中vector容器详解

    参考链接:https://www.runoob.com/w3cnote/cpp-vector-container-analysis.html 一.什么是vector? 向量(Vector)是一个封装了 ...