golang学习笔记(22)-jwt-go

本文详细介绍了JSON Web Token(JWT)的工作原理,包括如何创建JWT、如何使用JWT进行签名以及如何解密JWT。通过示例代码展示了在Go语言中使用jwt-go库创建和解析JWT的过程,涵盖了JWT的header、payload和signature三个部分。同时,解释了JWT的生命周期和验证机制,强调了在前后端交互中的安全使用。
摘要由CSDN通过智能技术生成

jwt-go

什么是jwt

全称为json web token,通过数字签名的方式,以json对象为载体,在不同的服务终端之间安全的传输信息,最常见的场景就是授权认证,一旦用户登录,后续的每个请求都会包含jwt,系统在每次处理用户请求之前,都要先经行jwt安全校验,通过后再经行处理。jwt由三个部分组成—header,payload,signature。

创建一个jwt

官方代码

mySigningKey := []byte("AllYourBase")

type MyCustomClaims struct {
	Foo string `json:"foo"`
	jwt.StandardClaims
}

// Create the Claims
claims := MyCustomClaims{
	"bar",
	jwt.StandardClaims{
		ExpiresAt: 15000,
		Issuer:    "test",
	},
}

token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
ss, err := token.SignedString(mySigningKey)
fmt.Printf("%v %v", ss, err)

逐步分析
创建一个带要求的jwt官方给的方法为NewWithClaims。
NewWithClaims方法为

func NewWithClaims(method SigningMethod, claims Claims) *Token {
	return &Token{
		Header: map[string]interface{}{
			"typ": "JWT",
			"alg": method.Alg(),
		},
		Claims: claims,
		Method: method,
	}
}

方法参数中,第一个参数为加密方法,第二个参数Claims是一个接口
其接口构造为

type Claims interface {
    Valid() error
}

其中实现了本接口的结构体有

type MapClaims map[string]interface{}
type StandardClaims struct {
	Audience  string `json:"aud,omitempty"`
	ExpiresAt int64  `json:"exp,omitempty"`
	Id        string `json:"jti,omitempty"`
	IssuedAt  int64  `json:"iat,omitempty"`
	Issuer    string `json:"iss,omitempty"`
	NotBefore int64  `json:"nbf,omitempty"`
	Subject   string `json:"sub,omitempty"`
}

其中NotBefore 表示生效时间,ExpiresAt 失效时间,Issuer签发者
先用StandardClaims 来实现一个Claims接口

type MyClaims struct {
	username string `json:"username"`
	jwt.StandardClaims
}

实例化

claims := MyClaims{
		Username: "logiee",
		StandardClaims: jwt.StandardClaims{
			NotBefore: time.Now().Unix() - 60,
			ExpiresAt: time.Now().Unix() + 60*60,
			Issuer:    "logiee",
		},
	}

加密方式暂时选用对称加密HS256
则NewWithClaims将生成一个token,先直接输出token

package main

import (
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"time"
)

type MyClaims struct {
	Username string `json:"username"`
	jwt.StandardClaims
}

func main() {
	claims := MyClaims{
		Username: "logiee",
		StandardClaims: jwt.StandardClaims{
			NotBefore: time.Now().Unix() - 60,
			ExpiresAt: time.Now().Unix() + 60*60,
			Issuer:    "logiee",
		},
	}
	t := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	fmt.Println(t)
}

在这里插入图片描述
这就是jwt中的header,payload,signature。
但现在前端无法接收这个格式,则需要改造成签名字符串。
官方提供方法SignedString

func (t *Token) SignedString(key interface{}) (string, error)

其中的参数key,官方要我们放在byte切片中
先设置一个自己的签名。

mySignKey := []byte("Allow")

执行签发

func main() {
	mySignKey := []byte("Allow")
	claims := MyClaims{
		Username: "logiee",
		StandardClaims: jwt.StandardClaims{
			NotBefore: time.Now().Unix() - 60,
			ExpiresAt: time.Now().Unix() + 60*60,
			Issuer:    "logiee",
		},
	}
	t := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	s, _ := t.SignedString(mySignKey)
	fmt.Println(s)
}

则可以获得一个完整的token
在这里插入图片描述

解密

官方提供方法ParseWithClaims (CustomClaimsType)
官方代码

tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c"

type MyCustomClaims struct {
	Foo string `json:"foo"`
	jwt.StandardClaims
}

// sample token is expired.  override time so it parses as valid
at(time.Unix(0, 0), func() {
	token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, func(token *jwt.Token) (interface{}, error) {
		return []byte("AllYourBase"), nil
	})

	if claims, ok := token.Claims.(*MyCustomClaims); ok && token.Valid {
		fmt.Printf("%v %v", claims.Foo, claims.StandardClaims.ExpiresAt)
	} else {
		fmt.Println(err)
	}
})

ParseWithClaims

func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error)

第一个参数为接收的token字符串,第二个参数claims与上文一样,第三个参数为函数参数,最为重要。
参数函数为

type Keyfunc func(*Token) (interface{}, error)

解析方法使用这个回调函数来提供验证的密钥。该函数接收已解析但未验证的Token。这允许你使用令牌头部的属性(如`kid’)来确定使用哪个密钥。

则解密代码

	withClaims, _ := jwt.ParseWithClaims(s, &MyClaims{}, func(token *jwt.Token) (interface{}, error) {
		return mySignKey, nil
	})
	fmt.Println(withClaims)

在这里插入图片描述
我们通过断言来获得myClaims中的username

withClaims, _ := jwt.ParseWithClaims(s, &MyClaims{}, func(token *jwt.Token) (interface{}, error) {
		return mySignKey, nil
	})
	fmt.Println(withClaims.Claims.(*MyClaims).Username)

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值