Golang/Gin-JWT身份验证

前言

如果我们编写的api不需要验证就可以随意调用,显然是不安全的。我们需要对用户进行身份验证,根据用户身份提供服务。这时候JWT就派上用场了。

作者水平有限,有任何问题欢迎在文章下方交流!

JWT验证简介

JSON Web Token(JWT)是一个开放的标准(RFC 7519),它定义了一个紧凑且自包含的方式,用于在各方之间作为JSON对象安全地传输信息。

JWT验证流程

1、前端使用账户密码等信息向服务器发送POST请求;

2、服务器使用私钥secret加密账户密码等信息,生成一个token,并返回给前端;

3、前端使用该token附带在请求参数中,向服务器发送各种请求;

4、服务器验证前端请求时附带的token,验证成功,则对前端请求进行处理。

JWT的组成

jwt的token由3部分组成:

1、头部(header)

2、载荷(payload)

3、签证(signature)

jwt解密网址:https://jwt.io/

在这里插入图片描述

头部

JWT的头部采用base64对称加密,包含两个信息:

{
  "alg": "HS256", //声明加密算法
  "typ": "JWT"  //声明类型,为JWT
}

载荷

载荷是存放有效信息的地方。

标准中注册的声明**(建议但不强制使用)** :

  • iss: jwt签发者

  • sub: jwt所面向的用户

  • aud: 接收jwt的一方

  • exp: jwt的过期时间,这个过期时间必须要大于签发时间

  • nbf: 定义在什么时间之前,该jwt都是不可用的.

  • iat: jwt的签发时间

  • jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

其他信息可自行添加,但是不建议存放敏感信息,因为base64是对称解密的,意味着只要拿到token就可以解密出载荷中存放的信息。

签证

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

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

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

注意:密钥secret是存储在服务端的,jwt的token的签发生成也是在服务端的,secret是用来进行token的签发和验证,所以,它就是你服务端的私钥,切忌泄露!一旦其他人得知这个secret,那就意味着他可以自己随意签发jwt了,十分危险。

JWT-hello world

package main

// jwt身份验证demo

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

// 设置jwt密钥secret
var jwtSecret=[]byte("123")

type  Claims struct {
	UserID 	 string `json:"userid"`
	jwt.StandardClaims
}

// GenerateToken 生成token的函数
func GenerateToken(userid string)(string,error){
	nowTime :=time.Now()
	expireTime:=nowTime.Add(3*time.Hour)

	claims:=Claims{
		userid,  // 自行添加的信息
		jwt.StandardClaims{
			ExpiresAt: expireTime.Unix(), // 设置token过期时间
			Issuer: "gin-blog",  // 设置jwt签发者
		},
	}
	// 生成token
	tokenClaims:=jwt.NewWithClaims(jwt.SigningMethodHS256,claims)
	token,err:=tokenClaims.SignedString(jwtSecret)

	return token,err
}

// ParseToken 验证token的函数
func ParseToken(token string)(*Claims,error){
	// 对token的密钥进行验证
	tokenClaims,err:=jwt.ParseWithClaims(token,&Claims{},func(token *jwt.Token)(interface{},error){
		return jwtSecret,nil
	})

	// 判断token是否过期
	if tokenClaims!=nil{
		if claims,ok:=tokenClaims.Claims.(*Claims);ok && tokenClaims.Valid{
			return claims,nil
		}
	}

	return nil,err
}

func main() {
	// 生成一个token
	token,_:=GenerateToken("12")
	fmt.Println("生成的token:",token)
	// 验证并解密token
	claim,err:=ParseToken(token)
	if err!=nil {
		fmt.Println("解析token出现错误:",err)
	}else if time.Now().Unix() > claim.ExpiresAt {
		fmt.Println("时间超时")
	}else {
		fmt.Println("userid:",claim.UserID)
	}
}

JWT在实际项目中的使用

1、token的签发一般是在用户登录时进行,用户请求登录成功后就给前端签发一个token,用于后续请求其他接口的身份验证。

2、其他接口的JWT验证可以编写成一个中间件,以下以Gin框架中间件为例:

func JWT() gin.HandlerFunc {
	return func(context *gin.Context) {
		// 获取token
		token := context.Query("token")
		if token == "" {
			context.JSON(http.StatusOK, gin.H{
				"isSuccess": false,
				"mesg": "没有携带token",
			})
			context.Abort()
			return
		} else {
			claims, err := ParseToken(token)
			if err != nil {
				context.JSON(http.StatusOK, gin.H{
					"isSuccess": false,
					"mesg": "token验证失败",
				})
				context.Abort()
				return
			} else if time.Now().Unix() > claims.ExpiresAt {
				context.JSON(http.StatusOK, gin.H{
					"isSuccess": false,
					"mesg": "token已过期",
				})
				context.Abort()
				return
			}
		}
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值