gRPC with JWT

grpc,with,jwt · 浏览次数 : 33

小编点评

**使用 gRPC 和 JWT 进行身份验证的步骤:** 1. **生成 JWT:** - 用户登录成功后,创建一个 JWT 并将其签发给用户。 - JWT 中包含用户身份信息、角色和权限等数据。 2. **在 gRPC 请求中包含 JWT:** - 客户端在 gRPC 请求中包含 JWT 的元数据(Metadata)。 - 该 Metadata 包含 Authorization 字段,指向 JWT 的 URL。 3. **验证 JWT:** - 服务端读取接收到的 JWT 并验证其有效性。 - 检查 JWT 的签名是否有效,验证中的claims字段是否包含正确的身份信息和权限。 4. **决策授权:** - 验证后的 JWT 信息用于决定是否允许用户访问请求的资源。 - 这可能涉及一些授权策略和业务逻辑。 **代码示例:** **go 服务端:** ```go import ( "context" "fmt" "github.com/golang-jwt/jwt/v5" ) func verifyToken(tokenString string) error { // Parse the JWT string. token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { // Check if the token is valid. if err != nil { return nil, errors.Wrap(err, "init token parser error") } // Get the claims from the token. claims, ok := token.Claims.(jwt.MapClaims) if !ok { return nil, errors.New("invalid claims") } // Get the expiration time of the token. exp, err := claims.GetExpirationTime() if err != nil { return nil, errors.Wrap(err, "GetExpirationTime from token error") } // Check if the token has expired. if now.Sub(exp) > 0 { return nil, errors.New("token expired") } // Return the claims. return claims, nil }) // Handle errors. if err != nil { return nil, err } // Return the JWT claims. return nil } ``` **go 客户端:** ```go import ( "context" "fmt" "github.com/golang-jwt/jwt/v5" ) func genToken() (string, error) { // Create a claims object with the necessary claims. claims := jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Issuer: "gRPC token", Subject: "gRPC example client", } // Create a JWT token with the claims. token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) // Return the JWT token. return token.SignedString([]byte("testKey")), nil } func main() { // Generate a token. token, err := genToken() if err != nil { panic(err) } // Create a gRPC client. conn, err := grpc.Dial("localhost:50001", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithPerRPCCredentials(&TokeAuth{Token: token})) if err != nil { panic(err) } client := pb.NewSayHiClient(conn) // Send a request to the server. resp, err := client.Hi(context.Background(), &pb.HelloRequest{Name: "Wang"}) if err != nil { panic(err) } // Print the response. fmt.Println(resp.String()) } ```

正文

在 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相似的内容:

gRPC with JWT

在 gRPC 中使用 JWT(JSON Web Tokens)进行身份验证是一种常见的做法,它可以帮助你确保请求方的身份和权限。下面是一种使用 gRPC 和 JWT 进行身份验证的步骤: 1. **生成和签发 JWT:** 在用户登录成功后,你需要生成一个 JWT 并将其签发给用户。JWT 中可以包

gRPC入门学习之旅(十)

gRPC是一个高性能、通用的开源远程过程调用(RPC)框架,基于底层HTTP/2协议标准和协议层Protobuf序列化协议开发, gRPC 客户端和服务端可以在多种环境中运行和交互。你可以用Java创建一个 gRPC 服务端,用 Go、Python、C# 来创建客户端。本系统文章详细描述了如何创建一...

gRPC入门学习之旅(九)

gRPC是一个高性能、通用的开源远程过程调用(RPC)框架,基于底层HTTP/2协议标准和协议层Protobuf序列化协议开发, gRPC 客户端和服务端可以在多种环境中运行和交互。你可以用Java创建一个 gRPC 服务端,用 Go、Python、C# 来创建客户端。本系统文章详细描述了如何创建一...

gRPC入门学习之旅(八)

gRPC是一个高性能、通用的开源远程过程调用(RPC)框架,基于底层HTTP/2协议标准和协议层Protobuf序列化协议开发, gRPC 客户端和服务端可以在多种环境中运行和交互。你可以用Java创建一个 gRPC 服务端,用 Go、Python、C# 来创建客户端。本系统文章详细描述了如何创建一...

[转帖]gRPC Load Balancing

https://www.cnblogs.com/charlieroro/p/14312362.html 翻译自:https://grpc.io/blog/grpc-load-balancing/ 这是gRPC负载均衡的第一篇,后续会给出基于golang XDS服务发现的例子,了解golang XDS

GRPC与 ProtoBuf 的理解与总结

转载请注明出处: 1.GRPC 官网:https://www.grpc.io/ gRPC 官方文档中文版:http://doc.oschina.net/grpc RPC 框架的目标就是让远程服务调用更加简单、透明,其负责屏蔽底层的传输方式(TCP/UDP)、序列化方式(XML/Json)和通信细节。

文盘Rust -- tonic-Rust grpc初体验

gRPC 是开发中常用的开源高性能远程过程调用(RPC)框架,tonic 是基于 HTTP/2 的 gRPC 实现,专注于高性能、互操作性和灵活性。该库的创建是为了对 async/await 提供一流的支持,并充当用 Rust 编写的生产系统的核心构建块。今天我们聊聊通过使用tonic 调用grpc的的具体过程。

gRPC入门

1. gRPC简介 gRPC是一种高性能、开源和通用的远程过程调用(RPC)框架,由Google开源并维护。它使用Protocol Buffers(protobuf)作为接口定义语言(IDL),提供跨平台、跨语言的RPC调用支持。gRPC具有以下几个特点: 高性能:使用HTTP/2协议,支持多路复用

gRPC vs. HTTP:网络通信协议的对比

## 概述 gRPC 和 HTTP 是两种常见的网络通信协议,用于在客户端和服务器之间进行通信。它们具有不同的特点和适用场景,下面对它们进行详细比较。 ## HTTP(Hypertext Transfer Protocol) ### 特点: 1. **简单易用**:HTTP 使用简单的请求方法和状态

gRPC如何保障数据安全传输

## 什么是 gRPC? gRPC 是由 Google 开发的高性能、开源的 RPC(Remote Procedure Call)框架,用于在客户端和服务器之间进行通信。它基于 Protocol Buffers(protobuf)进行消息序列化和反序列化,支持多种通信协议,如 HTTP/2、TCP