go使用jwt对前端用户身份通过token认证

文章目录

    • 一、导入工具包jwt-go生成token
    • 二、在登录验证接口中使用token生成方法
    • 三、解析前端请求头中的token
    • 四、中间件来验证客户端传递过来的token
    • 五、使用示例

背景前沿:近期项目需要对前端提供的部分接口做身份认证拦截,需要在登录成功后生成一个token返回给前端,后续需要进行验证的接口需要在请求头中携带token才能正常请求数据

一、导入工具包jwt-go生成token

  1. 命令导入安装包
go get -u github.com/dgrijalva/jwt-go
  1. 可在使用时包头直接引入
"github.com/dgrijalva/jwt-go"
  1. 一些后续使用时需要的基础结构体
// JwtClaims 创建自己的Claims
type JwtClaims struct {
	*jwt.StandardClaims
	//用户编号
	UID      string
	Username string
}

// 登录的参数
type UserLogin struct {
	UserName  string  `json:"user_name"`  //用户名
	Password  string  `json:"password"`   //密码,对明文密码进行sha256
}
var (
	//盐
	secret                 = []byte("wondersafebox") // 后续加密增加盐增加复杂度
	TokenExpired     error = errors.New("Token is expired") // token错误类型提炼
	TokenNotValidYet error = errors.New("Token not active yet") // token错误类型提炼
	TokenMalformed   error = errors.New("That's not even a token") // token错误类型提炼
	TokenInvalid     error = errors.New("Couldn't handle this token:") // token错误类型提炼
)
  1. 定义生成token的方法
// CreateJwtToken 生成一个jwttoken
func CreateJwtToken(id string, username string) (string, error) {

	// 定义过期时间,7天后过期
	expireToken := time.Now().Add(time.Hour * 24 * 7).Unix()

	claims := JwtClaims{
		&jwt.StandardClaims{
			NotBefore: int64(time.Now().Unix() - 1000), // token信息生效时间
			ExpiresAt: int64(expireToken), // 过期时间
			Issuer:    "wonders", // 发布者
		},
		id,
		username,
	}
	// 对自定义claims加密,jwt.SigningMethodHS256是加密算法得到第二部分
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	// 给这个token盐加密 第三部分,得到一个完整的三段的加密
	signedToken, err := token.SignedString(secret)
	if err != nil {
		return "", err
	}
	return signedToken, nil
}

二、在登录验证接口中使用token生成方法

在登录验证时,首先校验完用户名和密码是否匹配,匹配生成后调用工具包jwt中的CreateJwtToken方法生成token返回给前端

// 用户登录
func UserLogin(c *gin.Context) {
	appG := app.Gin{C: c}

	//1.解析footprint Body参数
	userLoginBody := new(models.UserLogin)
	if err := c.ShouldBindJSON(userLoginBody); err != nil {
		appG.Response(models.ErrorArgs, "参数错误", err.Error())
		return
	}
	// 一些用户名、密码校验业务代码
	... ...
	//password := sha256.Sum256([]byte(userLoginBody.Password)) // sha256加密
	//passwordStr:=hex.EncodeToString(password[:]) // 转为字符串
	// 参数Password(前端已经做sha256加密)与查询到的用户密码做比较是否一直
	if userData["password"] != userLoginBody.Password {
		appG.Response(models.ErrorFormatPassword, "用户密码错误", err.Error())
		return
	}
	// 登录成功生成token
	token, err := jwt.CreateJwtToken(userData["account_id"].(string), userData["user_name"].(string))
	if err != nil {
		appG.Response(models.ErrorToken, "生成token失败", err.Error())
		return
	}
	// 登录成功返回前端生成的token
	appG.Response(models.Success, "登录成功", token)
}

前端后续接口需要携带返回的token在请求头中,便于后续访问

三、解析前端请求头中的token

ParseJwtToken方法与CreateJwtToken方法可一起放在自建的工具包jwt中便于调用

// ParseJwtToken 解析token得到是自己创建的Claims
func ParseJwtToken(jwtToken string) (*JwtClaims, error) {
	var jwtclaim = &JwtClaims{}
	_, err := jwt.ParseWithClaims(jwtToken, jwtclaim, func(*jwt.Token) (interface{}, error) {
		//得到盐
		return secret, nil
	})
	if err != nil {
		if ve, ok := err.(*jwt.ValidationError); ok {
			if ve.Errors&jwt.ValidationErrorMalformed != 0 {
				return nil, TokenMalformed
			} else if ve.Errors&jwt.ValidationErrorExpired != 0 {
				// Token is expired
				return nil, TokenExpired
			} else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
				return nil, TokenNotValidYet
			} else {
				return nil, TokenInvalid
			}
		}
	}
	return jwtclaim, nil
}

四、中间件来验证客户端传递过来的token

在众多接口都需要验证前端token的情况下,我们可以写一个中间件,在请求访问之前先统一对请求头中的token值进行验证,成功之后再进行后续请求响应,反正直接返回请求头错误,拒绝访问

// 校验token中间件
func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 从请求头中获取token
		tokeString := c.GetHeader("token")
		fmt.Println(tokeString, "当前token")
		if tokeString == "" {
			c.JSON(http.StatusOK, gin.H{
				"code":    1005,
				"message": "必须传递token",
			})
			c.Abort()
			return
		}
		claims, err := jwt.ParseJwtToken(tokeString)
		if err != nil {
			c.JSON(http.StatusOK, gin.H{
				"code":    1005,
				"message": "token解析错误",
			})
			c.Abort()
			return
		}
		// 从token中解析出来的数据挂载到上下文上,方便后面的控制器使用
		c.Set("userId", claims.UID)
		c.Set("userName", claims.Username)
		c.Next()
	}
}

五、使用示例

在路由中使用如下,先登录校验生成token,再在需要验证token的接口前进行验证token

参考博文:
gin框架使用jwt对前端用户身份认证
Golang Gin框架使用JWT实现简单身份验证
golang之JWT实现

你可能感兴趣的:(go,golang,jwt,http)