设为首页 加入收藏

TOP

gRPC with JWT(一)
2023-09-09 10:25:40 】 浏览:260
Tags:gRPC with JWT

在 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/inse
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Go 输出函数 下一篇Go语言-Slice详解

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目