JWT详解

在这里插入图片描述

什么是JWT

JWT是一个非常轻巧的规范,这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息,一个JWT由三部分组成,Header头部、Claims载荷、Signature签名

在这里插入图片描述

JWT (header)

JWT头部承载两部分信息

  • 令牌类型:JWT
  • 加密算法:通常直接使用HMAC SHA256
{
"alg": "HS256",
"typ": "JWT"
}

有效载荷 (payload)

有效载荷部分是JWT的主体内容(存放有效信息),同样也是一个json对象,JWT指定了七个默认字段供选择

  • 发行人:iss
  • 到期时间:exp
  • 主题:sub
  • 用户(受众):aud
  • 生效时间:nbf
  • 签发时间:iat
  • 唯一标识(编号):jti

默认JWT是未加密的,然和人都可以解读其内容,不要存放私密敏感信息

这个payloadJson对象也会使用base64URL算法转化为字符串保存

{
  "ExpiresAt":time.Now().Add(7*24*time.Hour)Unix(),	//过期时间
	"IssuedAt":time.Now().Unix(),		//发放时间
	"Issuer":"admin",
	"Subject":"user-token"
}

签名 (signature):对前两部分通过指定的算法生成hash,防止被篡改

签名信息有三部分组成,并通过.连接:

  • base64UrlEncode(header)
  • base64UrlEncode(payload)
  • secret
  HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

Base64URL

Base64URL 是一种能够对 URL 进行 base64 串型化的算法。

Base64中用的三个字符是"+","/“和”=",由于在URL中有特殊含义,会与特殊符号+、/和=冲突,Base64URL会将 =省略、+替换成-,/替换成_。这就是base64URL算法

注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。

算出签名后,将这三部分用.连接成一个完整的字符串,构成了最终的JWT

在这里插入图片描述

JWT使用

在这里插入图片描述

客户端接收服务器返回的JWT,将其存储在Cookie或localStorage中。

此后,客户端将在与服务器交互中都会带JWT。如果将它存储在Cookie中,就可以自动发送,但是不会跨域,因此一般是将它放入HTTP请求的请求头Authorization字段中。

Authorization: Bearer <token>

当跨域时,也可以将JWT被放置于POST请求的数据主体中。

JWT特点

  • 因为json的通用性,所以JWT是可以进行跨语言支持的,所以像java、js、php、go很多语言都可以使用。

  • JWT默认不加密,但可以加密。生成原始令牌后,可以使用改令牌再次对其进行加密。

  • 因为有了payload部分,JWT不仅可用于认证,还可用于存储一些业务逻辑所必要分非敏感信息。善用JWT有助于减少服务器请求数据库的次数

  • 便于传输,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的。

  • 它不需要在服务端保存会话信息, 所以它易于应用的扩展

  • JWT 不加密的情况下,不能将私密数据写入 JWT。

  • JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。

  • JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。

  • 为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。

参考连接

  • http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html
  • https://github.com/dwyl/learn-json-web-tokens/blob/master/README.md

上代码!!!

//yaml中
# 身份验证配置
# jwt configuration
jwt:
  signing-key: 'ly_Vlearn'


type Claims struct {
	UserId uint
  	UUID uuid.UUID
	jwt.StandardClaims
}

//登录以后签发jwt
func tokenNext(c *gin.Context, user model.User) (string,error){
	j := &middleware.JWT{
    // 唯一签名
		[]byte(global.GVA_CONFIG.JWT.SigningKey), 
	}
	clams := request.CustomClaims{
		UUID:        user.UUID,
		ID:          user.UserId,
		StandardClaims: jwt.StandardClaims{
      //签名生效时间
			NotBefore: int64(time.Now().Unix() - 1000),       
      //发放时间
			IssuedAt:time.Now().Unix(),
      //过期时间
			ExpiresAt: int64(time.Now().Unix() + 60*60*24*7), 
      //签名的发行者
			Issuer:    "ldy",                              
		},
	}
  token:=jwt.NewWithClaims(jwt.SigningMethodHS256,claims)
  tokenString,err:=token.SignedString(jwtkey)
  if err != nil {
     return "",err
  }
  return tokenString,nil
}

====================================================================

//验证前端给的Token
func AuthMiddleware()gin.HandlerFunc  {

	return func(context *gin.Context) {
		//获取 header
		tokenString:=context.GetHeader("Authorization")

		//验证格式
		if tokenString==""|| !strings.HasPrefix(tokenString,"Bearer ") {
			context.JSON(http.StatusUnauthorized,gin.H{
				"code":401,
				"msg":"权限不足",
			})
			context.Abort()
			return
		}

		tokenString=tokenString[7:]
		//验证tokenString
		token,claims,err:=common.ParseToken(tokenString)
		if err != nil|| !token.Valid{
			context.JSON(http.StatusUnauthorized,gin.H{
				"code":401,
				"msg":"权限不足",
			})
			context.Abort()
			return
		}

		//通过验证
		userId:=claims.UserId
		DB:=common.GetDB()
		var user model.User
		DB.First(&user,userId)

		//用户不存在
		if user.ID==0 {
			context.JSON(http.StatusUnauthorized,gin.H{
				"code":401,
				"msg":"权限不足",
			})
			context.Abort()
			return
		}
		//将用户信息写入上写文
		context.Set("user",user)

		context.Next()
	}

//具体验证token方法
func ParseToken(tokenStr string) (*jwt.Token,*Claims,error) {
	claims:=&Claims{}
	token,err:=jwt.ParseWithClaims(tokenStr,claims, func(token *jwt.Token) (i interface{}, err error) {
		return jwtkey,nil
	})
	return token,claims,err
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值