JWT后台实现旧Token失效的问题(添加黑名单方式)

背景:   在开发设计中涉及到JWT的校验问题,但是发现一个漏洞同时也是JWT设计的理念,那就是后端不进行相关的Token存储,后端只进行相关的Token验证,同时还有就是token的生成和刷新,那么问题来了,那就是后端校验不会知道是否是最新的token

也就是说,可能已经刷新过了token,但是发现旧的token还没过期,这个时候还可以进行使用,在我看来还是有安全风险的,我想要的设计是用户退出登录或者刷新Token后,旧的token要立即失效,这样才够安全,不然一旦被黑客拿到旧的token,那么它就可以利用旧的token一直刷新使用,

后果很严重。

 

设计的理念:  添加Redis作为黑名单进行绑定,旧的Token,设计理念借鉴了下面博客:

https://blog.csdn.net/weixin_39851884/article/details/104825253

下面是我设计的具体的流程图:(不过我没有考虑旧的token过期时间问题,所以也可以进行对存储在Redis中的数据进行相关的时间设定,也就是旧的token过期时间到了,redis中的数据自动清除,这样也可以对Redis进行相关的维护,不然时间越长Redis的压力越大。)

具体的实现:(login登录就不做处理了,因为就是正常的获取Token的业务,很简单,如果没有基础可以参考我之前的博客)

      主函数注册API接口并启动服务器

func main() {
	r := gin.Default()
	r.GET("/login", login)
	r.GET("/refresh", refresh)
	r.GET("/sayHello", sayHello)
	r.Run(":9090")

	//测试URL实例
	//http://localhost:9090/login?username=dong&password=123456
	//http://localhost:9090/verify?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NjA1MTIyMTAsImlhdCI6MTU2MDUwODYxMCwidXNlcl9pZCI6MSwicGFzc3dvcmQiOiIxMjM0NTYiLCJ1c2VybmFtZSI6ImRvbmciLCJmdWxsX25hbWUiOiJkb25nIiwicGVybWlzc2lvbnMiOltdfQ.Esh1Zge0vO1BAW1GeR5wurWP3H1jUIaMf3tcSaUwkzA
	//http://localhost:9090/refresh?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NjA1MTIyNDMsImlhdCI6MTU2MDUwODYxMCwidXNlcl9pZCI6MSwicGFzc3dvcmQiOiIxMjM0NTYiLCJ1c2VybmFtZSI6ImRvbmciLCJmdWxsX25hbWUiOiJkb25nIiwicGVybWlzc2lvbnMiOltdfQ.Xkb_J8MWXkwGUcBF9bpp2Ccxp8nFPtRzFzOBeboHmg0
}

       以刷新token,让旧Token失效的方式(退出登录的方式相同,这里面对redis存储的数据进行了时间的处理,也就是会根据过期时间将数据彻底清空掉)

/**
 * @Description: 功能描述(刷新JWT的token)
 * @Date : 2020/11/12
 */
func refresh(c *gin.Context) {
	strToken := c.Query("token")
	claims, err := verifyAction(strToken)
	if err != nil {
		c.String(http.StatusNotFound, err.Error())
		return
	}
	// 获取失效时间,填充到Redis中。
	a := int(claims.ExpiresAt - time.Now().Unix())  //剩余过期时间
	utils.Set(strToken, "1", a)  //存在Redis中的数据,对应的过期时间为:a表示秒
	claims.ExpiresAt = time.Now().Unix() + (claims.ExpiresAt - claims.IssuedAt) // 失效的时间
	signedToken, err := getToken(claims)
	if err != nil {
		c.String(http.StatusNotFound, err.Error())
		return
	}
	c.String(http.StatusOK, signedToken)
}

     具体的业务实现:(会进行判断Redis中的是否存在该数据,如果不存在则表明没有加入黑名单,否则就是加入了黑名单)

/**
 * @Description: 功能描述(业务测试,用于真正的开发业务验证是否用户合法,然后执行Hello业务)
 * @Date : 2020/11/12
 */
func sayHello(c *gin.Context) {
	strToken := c.Query("token")
	fmt.Println("token=", strToken)
	flag := utils.GetStringValue(strToken)
	fmt.Println("flag =", flag)
	if flag == "1" {
		c.JSON(http.StatusBadRequest, errors.New(ErrorReason_ReLogin))
		c.Abort()
		return
	}
	claim, err := verifyAction(strToken)
	if err != nil {
		c.String(http.StatusNotFound, err.Error())
		return
	}
	if claim.Role == "admin" {
		fmt.Println("该用户是管理员可以执行相关的业务")
		fmt.Println("--------------执行Hello业务--------------")
	}

	c.JSON(http.StatusOK, claim)
}

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JWT实现token销毁的方式有几种方法。一种常见的方法是将token存储在服务器端的黑名单中。当用户注销或需要销毁token时,将该token添加黑名单中。在每次请求时,服务器会检查token是否在黑名单中,如果是,则拒绝该请求。这种方法需要服务器维护一个黑名单列表,并增加一些额外的逻辑来检查token的有效性。\[2\] 另一种方法是使用token的过期时间来实现销毁。在生成token时,可以设置一个过期时间,一旦token过期,它将自动失效。这样,即使token被保留在客户端,一旦过期,它也无法再被使用。这种方法不需要服务器维护黑名单列表,但需要在生成token时设置合适的过期时间。\[3\] 需要注意的是,JWT本身是无状态的,它不提供直接的注销功能。因此,实现token销毁需要额外的逻辑和控制。具体的实现方式可以根据具体的需求和系统架构来选择。 #### 引用[.reference_title] - *1* [SpringBoot集成JWT实现token验证,token注销](https://blog.csdn.net/yangyangye/article/details/117445245)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [如何使用jwt 完成注销(退出登录)功能](https://blog.csdn.net/weixin_39813433/article/details/122287823)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值