在 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. PPT 常见的页面框架

    分割 分列 居中 包围 对称 杂志 https://www.bilibili.com/video/BV1ha411g7f5?p=19

  2. 在 SDXL 上用 T2I-Adapter 实现高效可控的文生图

    T2I-Adapter 是一种高效的即插即用模型,其能对冻结的预训练大型文生图模型提供额外引导.T2I-Adapter 将 T2I 模型中的内部知识与外部控制信号结合起来.我们可以根据不同的情况训练各 ...

  3. PS 独立集中标识下修改项目采购类型增强

    1.当物料独立集中标识为2,采购类型通过BAPI:BAPI_NETWORK_COMP_ADD,type_of_pur_resv传入'7',则报错"组件分配并不是未销售订单或项目库存而设的&q ...

  4. Python使用pandas库读取txt文件中的Json数据,并导出到csv文件

    使用的是 Python 3 代码: #!/usr/bin/python # -*- coding: gbk -*- # JSON数据导出到csv文件 import json import pandas ...

  5. [kuangbin] 专题13 基础计算几何 题解 + 总结

    kuangbin带你飞:点击进入新世界 [kuangbin] 专题7 线段树 题解 + 总结:https://www.cnblogs.com/RioTian/p/13413897.html kuang ...

  6. 叮~OpenSCA社区拍了拍您并发来一份开源盛会邀请函

    2023数字供应链安全大会(DSS 2023)将于8月10日在北京·国家会议中心举办.本次大会以"开源的力量"为主题,由悬镜安全主办,ISC互联网安全大会组委会.中国软件评测中心( ...

  7. <vue 路由 5、动态路由-标签上传递参数>

    一.效果 在about页面点击"我的",路径里传入了参数zhangsan,在"我的"页面里接收传递过来的张三并展现出来.注:标签中传递参数写法 二.代码结构 注 ...

  8. Vue - 组件通信(父子单向传递、父子相互传递、祖孙隔代传递)

    父组件向子组件单向传递 父组件:引入子组件后,通过属性绑定的形式,将值传入子组件: ` ` 子组件:子组件通过props接收父组件传入的值; ` {{sonGetParam}} ` 子组件向父组件单向 ...

  9. Angular系列教程之MVC模式和MVVM模式

    .markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...

  10. 【SI】source insight4 添加指定类型的文件

    Options->File Type Options 红框可选择是否将指定类型的文件添加到工程 绿框可添加自定义文件类型,如汇编*.s;*.S 蓝框可新增文件类别,用于自定义文件类型 如不需将t ...