引言

Json web token (JWT) 是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

jwt构成

JWT是由三段信息构成的,将这三段信息文本用.链接一起就构成了Jwt字符串,就像这样

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IjEiLCJkaWZmZXJlbnRpYXRlIjoiMSIsImV4cCI6MTYzNjUyMTYzNywiaXNzIjoiTWljcm9zZXJ2aWNlLkJGRiJ9.5LQ_mBJLkHUxjSqoE8evh7_UahrK8WqLgvhpZ2HIIiI

第一部分我们称它为头部(header),第二部分我们称其为载荷(payload),第三部分是签证(signature)

header

jwt的头部承载两部分信息

typ:声明类型

alg:声明加密的算法

然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分.

playload

载荷就是存放有效信息的地方,这些有效信息包含三个部分

  • 标准中注册的声明
  • 公共声明
  • 私有声明

标准声明(建议但不强制使用):

  • iss: jwt签发者
  • sub: jwt所面向的用户
  • aud: 接收jwt的一方
  • exp: jwt的过期时间,这个过期时间必须要大于签发时间
  • nbf: 定义在什么时间之前,该jwt都是不可用的.
  • iat: jwt的签发时间
  • jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

公共声明:

公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.

私有声明:

私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。


然后将其进行base64加密,得到Jwt的第二部分。

signature

jwt的第三部分是一个签证信息,这个签证信息由三部分组成:

  • header(base64后的)
  • payload(base64后的)
  • secret

    此部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。

将这三部分用.连接成一个完整的字符串,构成了最终的jwt

在kratos框架中的使用

实现jwt自签逻辑

新建auth授权方法,可以在用户登录成功后调用Auth方法传入参数后返回jwt

package biz

import (
"kanxun_bff/internal/conf"
"time" "github.com/golang-jwt/jwt"
jwtv4 "github.com/golang-jwt/jwt/v4"
) type AuthUseCase struct {
key string
} func NewAuthUseCase() *AuthUseCase {
return &AuthUseCase{
key: "testKey",
}
} type MyClaims struct {
UserName string `json:"username"`
jwtv4.StandardClaims
} func (receiver AuthUseCase) Auth(username string) (string, error) {
myClaims := MyClaims{
username,
jwtv4.StandardClaims{
ExpiresAt: time.Now().Add(time.Hour * 2).Unix(), //设置JWT过期时间,此处设置为2小时
Issuer: conf.GetConfig().GetString("project.name"), //设置签发人
},
}
claims := jwt.NewWithClaims(jwt.SigningMethodHS256, myClaims)
//加盐
return claims.SignedString([]byte(receiver.key))
}

自定义jwt中间件

本文使用自定义jwt中间件,未使用kratos官方提供的jwt

kratos jwt middleware

// NewAuthServer jwt Server中间件
func NewAuthServer(authUc *biz.AuthUseCase) func(handler middleware.Handler) middleware.Handler {
return func(handler middleware.Handler) middleware.Handler {
return func(ctx context.Context, req interface{}) (reply interface{}, err error) {
var jwtToken string
if md, ok := metadata.FromIncomingContext(ctx); ok {
jwtToken = md.Get("x-md-global-jwt")[0]
} else if header, ok := transport.FromServerContext(ctx); ok {
jwtToken = strings.SplitN(header.RequestHeader().Get("Authorization"), " ", 2)[1]
} else {
// 缺少可认证的token,返回错误
return nil, auth.ErrAuthFail
}
token, err := authUc.CheckJWT(jwtToken)
if err != nil {
// 缺少合法的token,返回错误
return nil, auth.ErrAuthFail
}
ctx = context.WithValue(ctx, "username", token["username"])
ctx = context.WithValue(ctx, "differentiate", token["differentiate"])
reply, err = handler(ctx, req)
return
}
}
} // NewAuthClient jwt Client中间件
func NewAuthClient(authUc *biz.AuthUseCase) middleware.Middleware {
return func(handler middleware.Handler) middleware.Handler {
return func(ctx context.Context, req interface{}) (interface{}, error) { if header, ok := transport.FromServerContext(ctx); ok {
//如果Token为空则生成token,如果
if header.RequestHeader().Get(authorizationKey) != "" {
jwtToken := strings.SplitN(header.RequestHeader().Get(authorizationKey), " ", 2)[1]
//元数据传递
ctx = metadata.AppendToOutgoingContext(ctx, "x-md-global-jwt", jwtToken) } else {
token, err := authUc.Auth(
req.(*user.GetUserNameRequest).Username,
req.(*user.GetUserNameRequest).Differentiate,
)
if err != nil {
return nil, jwt.ErrGetKey
}
ctx = metadata.AppendToOutgoingContext(ctx, "x-md-global-jwt", token)
}
}
return handler(ctx, req)
}
}
}

路由白名单与jwt中间件的引入

//client
conn, err := grpc.DialInsecure(
context.Background(),
grpc.WithEndpoint("discovery:///xxx.xxx.grpc"),
grpc.WithDiscovery(r),
grpc.WithMiddleware(
recovery.Recovery(),
logging.Client(logger), //日志中间件,
tracing.Client(), //链路追踪中间件
metadata.Client(), //元数据传递中间件
jwt.NewAuthClient(authUc), //jwt中间件
),
) //server
var opts = []grpc.ServerOption{
grpc.Middleware(
recovery.Recovery(), //异常恢复中间件
tracing.Server(), //链路追踪中间件
logging.Server(logger), //日志中间件
metrics.Server(), //监控中间件
validate.Validator(), //参数校验
metadata.Server(), //元数据中间件
selector.Server( //jwt中间件
jwt.NewAuthServer(authUc),
).Match(func(operation string) bool {
// 白名单
r, err := regexp.Compile("/api.user.v1.User/GetUserName")
if err != nil {
// 自定义错误处理
return true
}
return r.FindString(operation) != operation
}).Build(),
),
}

下游服务获取用户信息

	value := ctx.Value("username")
fmt.Println(value)

如有错误请留言反馈

References

https://www.jianshu.com/p/576dbf44b2ae

https://zhuanlan.zhihu.com/p/86937325

https://go-kratos.dev/docs/component/middleware/auth

https://go-kratos.dev/docs/component/metadata

go微服务框架Kratos笔记(七)使用jwt认证中间件的更多相关文章

  1. go微服务框架Kratos笔记(一)入门教程

    kratos简介 Kratos 一套轻量级 Go 微服务框架,包含大量微服务相关功能及工具 本文基于kratos v2.0.3,windows平台,其他系统平台均可借鉴参考 环境搭建 Golang开发 ...

  2. go微服务框架Kratos笔记(六)链路追踪实战

    什么是链路追踪 借用阿里云链路追踪文档来解释 分布式链路追踪(Distributed Tracing),也叫 分布式链路跟踪,分布式跟踪,分布式追踪 等等,它为分布式应用的开发者提供了完整的调用链路还 ...

  3. go微服务框架Kratos笔记(三)引入GORM框架

    介绍 GORM是一个使用Go语言编写的ORM框架.中文文档齐全,对开发者友好,支持主流数据库. GORM官方文档 安装 go get -u github.com/jinzhu/gorm 在kratos ...

  4. go微服务框架kratos学习笔记七(kratos warden 负载均衡 balancer)

    目录 go微服务框架kratos学习笔记七(kratos warden 负载均衡 balancer) demo demo server demo client 池 dao service p2c ro ...

  5. kratos微服务框架学习笔记一(kratos-demo)

    目录 kratos微服务框架学习笔记一(kratos-demo) kratos本体 demo kratos微服务框架学习笔记一(kratos-demo) 今年大部分时间飘过去了,没怎么更博和githu ...

  6. go微服务框架kratos学习笔记五(kratos 配置中心 paladin config sdk [断剑重铸之日,骑士归来之时])

    目录 go微服务框架kratos学习笔记五(kratos 配置中心 paladin config sdk [断剑重铸之日,骑士归来之时]) 静态配置 flag注入 在线热加载配置 远程配置中心 go微 ...

  7. # go微服务框架kratos学习笔记六(kratos 服务发现 discovery)

    目录 go微服务框架kratos学习笔记六(kratos 服务发现 discovery) http api register 服务注册 fetch 获取实例 fetchs 批量获取实例 polls 批 ...

  8. go微服务框架kratos学习笔记四(kratos warden-quickstart warden-direct方式client调用)

    目录 go微服务框架kratos学习笔记四(kratos warden-quickstart warden-direct方式client调用) warden direct demo-server gr ...

  9. go微服务框架kratos学习笔记八 (kratos的依赖注入)

    目录 go微服务框架kratos学习笔记八(kratos的依赖注入) 什么是依赖注入 google wire kratos中的wire Providers injector(注入器) Binding ...

随机推荐

  1. 基于go语言学习工厂模式

    工厂模式 简单工厂模式(Simple Factory) 定义 优点 缺点 适用范围 代码实现 工厂方法模式(Factory Method) 定义 优点 缺点 适用范围 代码实现 抽象工厂模式(Abst ...

  2. transformers---BERT

    transformers---BERT BERT模型主要包括两个部分,encoder和decoder,encoder可以理解为一个加强版的word2vec模型,以下是对于encoder部分的内容 预训 ...

  3. CF487E Tourists + 圆方树学习笔记(圆方树+树剖+线段树+multiset)

    QWQ果然我已经什么都学不会的人了. 这个题目要求的是图上所有路径的点权和!QWQ(我只会树上啊!) 这个如果是好啊 这时候就需要 圆方树! 首先在介绍圆方树之前,我们先来一点简单的前置知识 首先,我 ...

  4. 洛谷4103 HEOI2014大工程(虚树+dp)

    又是一道虚树好题啊 我们建出来虚树,然后考虑dp过程,我们分别令\(sum[x],mndis[x],mxdis[x],size[x]\)为子树内的路径长度和,最短链,最长链,子树内关键点个数. 对于一 ...

  5. mysql join语句的执行流程是怎么样的

    mysql join语句的执行流程是怎么样的 join语句是使用十分频繁的sql语句,同样结果的join语句,写法不同会有非常大的性能差距. select * from t1 straight_joi ...

  6. C#特性知识图谱-二、事件

    C#特性知识图谱-二.事件 二.事件 在事件驱动的软件系统中,符合某种预设条件的情形出现是,一个事件就会被触发. 2.1 事件三要素 事件源:激发事件的对象 事件信息:事件本身说携带的信息 事件响应者 ...

  7. k8s 关于Job与Cronjob

    在Kubernetes 中通过创建工作负载资源 Job 可完成大型计算以及一些批处理任务.比如 Job 转码文件.获取部分文件和目录,机器学习中的训练任务等.这篇小作文我们一起来了解 k8s 中关于 ...

  8. 【Spring】重新认识 IoC

    前言 IoC (Inversion of control) 并不是Spring特有的概念. IoC 维基百科的解释: In software engineering, inversion of con ...

  9. 面试题系列:new String("abc")创建了几个对象

    new String("abc")创建了几个对象 面试官考察点猜想 这种问题,考察你对JVM的理解程度.涉及到常量池.对象内存分配等问题. 涉及背景知识详解 在分析这个问题之前,我 ...

  10. 【二食堂】Alpha - Scrum Meeting 4

    Scrum Meeting 4 例会时间:4.14 12:30 - 12:50 进度情况 组员 昨日进度 今日任务 李健 1. 主页面的搭建工作issue 1. 完成主页搭建**issue2. 与后端 ...