- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
本文地址 https://www.cnblogs.com/zichliang/p/17303759.html 。
github地址: https://github.com/dgrijalva/jwt-go 。
什么是JSON Web Token? JSON Web Token(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于在各方之间以JSON方式安全地传输信息。由于此信息是经过数字签名的,因此可以被验证和信任。可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对对JWT进行签名。 直白的讲jwt就是一种用户认证(区别于session、cookie)的解决方案.
优点:
缺点: 1、用户无法主动登出,只要token在有效期内就有效。这里可以考虑redis设置同token有效期一直的黑名单解决此问题.
2、token过了有效期,无法续签问题。可以考虑通过判断旧的token什么时候到期,过期的时候刷新token续签接口产生新token代替旧token 。
Header是头部 Jwt的头部承载两部分信息: 声明类型,这里是jwt 声明加密的算法 通常直接使用 HMAC SHA256 。
playload可以填充两种类型数据 简单来说就是 比如用户名、过期时间等, 。
iss: 签发者 sub: 面向的用户 aud: 接收方 exp: 过期时间 nbf: 生效时间 iat: 签发时间 jti: 唯一身份标识 。
是由header、payload 和你自己维护的一个 secret 经过加密得来的 签名的算法:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
go get -u github.com/golang-jwt/jwt/v4
这里注意 **最新版是V5 但是我们使用的V4, V5 的用法 也一样 不过需要实现Claims的接口方法 一共有六个左右。并且更加严谨了 ** 。
注册声明是JWT声明集的结构化版本,仅限于注册声明名称 。
type JwtCustomClaims struct {
ID int
Name string
jwt.RegisteredClaims
}
首先需要初始化Clamins 其次在初始化结构体中注册并且设置好过期时间 主题 以及生成时间等等。。 然后会发现 jwt.RegisteredClaims 在这个方法中 还需要实现Claims接口 还需要定义几个方法 如上图所示 然后我们使用 使用HS256 的签名加密方法使用指定的签名方法和声明创建一个新的[Token] 代码如下 。
// 本文地址 https://www.cnblogs.com/zichliang/p/17303759.html
// GenerateToken 生成Token
func GenerateToken(id int, name string) (string, error) {
// 初始化
iJwtCustomClaims := JwtCustomClaims{
ID: id,
Name: name,
RegisteredClaims: jwt.RegisteredClaims{
// 设置过期时间 在当前基础上 添加一个小时后 过期
ExpiresAt: jwt.NewNumericDate(time.Now().Add(viper.GetDuration("jwt.TokenExpire") * time.Millisecond)),
// 颁发时间 也就是生成时间
IssuedAt: jwt.NewNumericDate(time.Now()),
//主题
Subject: "Token",
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, iJwtCustomClaims)
return token.SignedString(stSignKey)
}
还有一个小坑 这里的 stsignKey 必须是byte字节的 所以我们在设置签名秘钥 必须要使用byte强转 像这个样子.
然后我们去执行 传入一个ID 和一个name 。
token, _ := utils.GenerateToken(1, "张三")
fmt.Println(token)
得到如下值 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJJRCI6MSwiTmFtZSI6IuW8oOS4iSIsIlJlZ2lzdGVyZWRDbGFpbXMiOnsic3ViIjoiVG9rZW4iLCJleHAiOjE2ODExODI2MDYsImlhdCI6MTY4MTE4MjYwNn19.AmOf60S2xby6GmlGgNo4Q5b01cRoAqXWhGorzxbJ2-Q 。
https://jwt.io/ 在写代码之前,我们把上面的token丢到上面网站中解析一下 可以发现 有三部分被解析出来了 。
代码解析token 。
// ParseToken 解析token
func ParseToken(tokenStr string) (JwtCustomClaims, error) {
// 声明一个空的数据声明
iJwtCustomClaims := JwtCustomClaims{}
//ParseWithClaims是NewParser().ParseWithClaims()的快捷方式
//第一个值是token ,
//第二个值是我们之后需要把解析的数据放入的地方,
//第三个值是Keyfunc将被Parse方法用作回调函数,以提供用于验证的键。函数接收已解析但未验证的令牌。
token, err := jwt.ParseWithClaims(tokenStr, &iJwtCustomClaims, func(token *jwt.Token) (interface{}, error) {
return stSignKey, nil
})
// 判断 是否为空 或者是否无效只要两边有一处是错误 就返回无效token
if err != nil && !token.Valid {
err = errors.New("invalid Token")
}
return iJwtCustomClaims, err
}
返回成功如下图所示 。
由于我们主动抛了个错,那我们如果手动传入错的token 看他是否会抛出错误提示呢?
jwtCustomClaim, err := utils.ParseToken(token + "12312323123")
结果:
答案是会.
package utils
import (
"errors"
"fmt"
"github.com/golang-jwt/jwt/v4"
"github.com/spf13/viper"
"time"
)
// 把签发的秘钥 抛出来
var stSignKey = []byte(viper.GetString("jwt.SignKey"))
// JwtCustomClaims 注册声明是JWT声明集的结构化版本,仅限于注册声明名称
type JwtCustomClaims struct {
ID int
Name string
RegisteredClaims jwt.RegisteredClaims
}
func (j JwtCustomClaims) Valid() error {
return nil
}
// GenerateToken 生成Token
func GenerateToken(id int, name string) (string, error) {
// 初始化
iJwtCustomClaims := JwtCustomClaims{
ID: id,
Name: name,
RegisteredClaims: jwt.RegisteredClaims{
// 设置过期时间 在当前基础上 添加一个小时后 过期
ExpiresAt: jwt.NewNumericDate(time.Now().Add(viper.GetDuration("jwt.TokenExpire") * time.Minute)),
// 颁发时间 也就是生成时间
IssuedAt: jwt.NewNumericDate(time.Now()),
//主题
Subject: "Token",
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, iJwtCustomClaims)
return token.SignedString(stSignKey)
}
// ParseToken 解析token
func ParseToken(tokenStr string) (JwtCustomClaims, error) {
iJwtCustomClaims := JwtCustomClaims{}
//ParseWithClaims是NewParser().ParseWithClaims()的快捷方式
token, err := jwt.ParseWithClaims(tokenStr, &iJwtCustomClaims, func(token *jwt.Token) (interface{}, error) {
return stSignKey, nil
})
if err == nil && !token.Valid {
err = errors.New("invalid Token")
}
return iJwtCustomClaims, err
}
func IsTokenValid(tokenStr string) bool {
_, err := ParseToken(tokenStr)
fmt.Println(err)
if err != nil {
return false
}
return true
}
go get -u "github.com/dgrijalva/jwt-go"
这里需要传入用户名和密码 然后根据SHA256 去进行加密 从而吧payload生成token 。
// 本文地址 https://www.cnblogs.com/zichliang/p/17303759.html
func Macke(user *Userinfo) (token string, err error) {
claims := jwt.MapClaims{ //创建一个自己的声明
"name": user.Username,
"pwd": user.Password,
"iss": "lva",
"nbf": time.Now().Unix(),
"exp": time.Now().Add(time.Second * 4).Unix(),
"iat": time.Now().Unix(),
}
then := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
token, err = then.SignedString([]byte("gettoken"))
return
}
在自己写的这个函数中 我们点进源码看返回值 解析方法使用此回调函数提供用于验证的键。函数接收已解析但未验证的令牌。 这允许您使用令牌Header中的属性(例如' kid ')来识别使用哪个键.
上述是源码的意思 而本人理解是制定一个类型规则然后去做解析。不然源码不知道你是制作token 还是解析token 。
func secret() jwt.Keyfunc {
//按照这样的规则解析
return func(t *jwt.Token) (interface{}, error) {
return []byte("gettoken"), nil
}
}
首先需要传入一个token,然后把解析规则传入 然后需要验证Token的正确性以及有效性。 如果二者都是没问题的 然后才能解析出 用户名和密码 或者是其他的一些值 。
// 解析token
func ParseToken(token string) (user *Userinfo, err error) {
user = &Userinfo{}
tokn, _ := jwt.Parse(token, secret())
claim, ok := tokn.Claims.(jwt.MapClaims)
if !ok {
err = errors.New("解析错误")
return
}
if !tokn.Valid {
err = errors.New("令牌错误!")
return
}
//fmt.Println(claim)
user.Username = claim["name"].(string) //强行转换为string类型
user.Password = claim["pwd"].(string) //强行转换为string类型
return
}
// 本文地址 https://www.cnblogs.com/zichliang/p/17303759.html
package main
import (
"errors"
"fmt"
"github.com/dgrijalva/jwt-go"
"time"
)
type Userinfo struct {
Username string `json:"username"`
Password string `json:"password"`
}
// Macke 生成jwt 需要传入 用户名和密码
func Macke(user *Userinfo) (token string, err error) {
claims := jwt.MapClaims{ //创建一个自己的声明
"name": user.Username,
"pwd": user.Password,
"iss": "lva",
"nbf": time.Now().Unix(),
"exp": time.Now().Add(time.Second * 4).Unix(),
"iat": time.Now().Unix(),
}
then := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
token, err = then.SignedString([]byte("gettoken"))
return
}
// secret 自己解析的秘钥
func secret() jwt.Keyfunc {
//按照这样的规则解析
return func(t *jwt.Token) (interface{}, error) {
return []byte("gettoken"), nil
}
}
// 解析token
func ParseToken(token string) (user *Userinfo, err error) {
user = &Userinfo{}
tokn, _ := jwt.Parse(token, secret())
claim, ok := tokn.Claims.(jwt.MapClaims)
if !ok {
err = errors.New("解析错误")
return
}
if !tokn.Valid {
err = errors.New("令牌错误!")
return
}
//fmt.Println(claim)
user.Username = claim["name"].(string) //强行转换为string类型
user.Password = claim["pwd"].(string) //强行转换为string类型
return
}
func main() {
var use = Userinfo{"zic", "admin*123"}
tkn, _ := Macke(&use)
fmt.Println("_____", tkn)
// time.Sleep(time.Second * 8)超过时间打印令牌错误
user, err := ParseToken(tkn)
if err != nil {
fmt.Println(err)
}
fmt.Println(user.Username)
}
本文地址 https://www.cnblogs.com/zichliang/p/17303759.html 。
这里需要注意 用户请求时带上token,服务器解析token后可以获得其中的用户信息,如果token有任何改动,都无法通过验证. 。
最后此篇关于Golang常用库之jwt-go的文章就讲到这里了,如果你想了解更多关于Golang常用库之jwt-go的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
本文主要给大家介绍Mysql数据库分库和分表方式(常用),涉及到mysql数据库相关知识,对mysql数据库分库分表相关知识感兴趣的朋友一起学习吧 1 分库 1.1 按照功能分库 按照功能进行
在当前对象由其他包含对象操作的系统中,当传递对当前对象的引用时,链接似乎一直在继续......没有任何结束(对于下面的代码,Car ->myCurrentComponent->myCar_Brake-
我有一个密码 UIAlertView,我们要求用户提供。我需要根据情况在不同的 View 上询问它,从 downloadViewController (用户下载数据后),当他们切换到他们的数据时(如果
我正在尝试编写一个函数,使得对于任何整数 x 的 P(x) 都有一个包含三个元素的列表,即平方、立方和 n 的四次方,但我仍然不知道如何组合然后制作一个函数,例如我有平方、立方体和 4 次幂函数下面是
关闭。这个问题需要更多 focused .它目前不接受答案。 关闭4年前。 锁定。这个问题及其答案是locked因为这个问题是题外话,但具有历史意义。它目前不接受新的答案或交互。 我能否列出一份常见的
Python 常用 PEP8 编码规范 代码布局 缩进 每级缩进用4个空格。 括号中使用垂直隐式缩进或使用悬挂缩进。 EXAMPLE: ?
关闭。这个问题需要更多focused .它目前不接受答案。 想改善这个问题吗?更新问题,使其仅关注一个问题 editing this post . 去年关闭。 Improve this questio
在经典 ui 中,您可以使用 xtype:cqinclude 包含来自不同路径的 rtePlugins,基本上为标准 RTE 插件创建一个位置,我如何在 Touch UI 中执行相同操作? 我尝试使用
在经典 ui 中,您可以使用 xtype:cqinclude 包含来自不同路径的 rtePlugins,基本上为标准 RTE 插件创建一个位置,我如何在 Touch UI 中执行相同操作? 我尝试使用
*strong text*我有多个网络应用程序使用了一些常见的依赖项,比如蒙戈连接器谷歌 Guava 乔达时间 我想到将它们从 webapp/WEB-INF/lib 中取出并放入一些 common-l
我正在编写一个 Web 服务器,我想知道哪些 HTTP 请求 header (由客户端发送)是最常见的,因此我应该重点实现。 目前,我只支持Accept 和Host。 最佳答案 不确定您的范围,但由于
我是一名优秀的程序员,十分优秀!