用户鉴权token的学习

157 阅读4分钟

在阅读了官方给定的API文档之后,我发现绝大多数的API请求都必须带上用户鉴权token,之前接触过但是没有仔细研究,正好通过这次机会好好学习一下

Token

1.什么是Token

当谈到“token”,我们指的是一种称为“令牌”的概念。在服务器与客户端交互中,它是由服务端生成的一串字符串,具有特殊意义,用于识别和验证客户端的请求。

一旦用户首次登录,服务器会创造一个独特的token,并将其发送给客户端。以后,客户端只需在请求数据时携带这个token,无需再提供用户名和密码。

这个token通常由几部分构成:首先是用户唯一身份标识(称为uid),用于确认用户的身份。接着是当前时间的时间戳,确保token的时效性。最后,为了加强安全性,token的前几位会经过哈希算法处理,压缩成一个固定长度的十六进制字符串,也被称为签名。这个签名的存在有助于防止token被泄露所带来的风险。

2.Token的原理

  1. 用户通过用户名和密码发送请求
  2. 程序校验
  3. 程序返回一个Token给客户端
  4. 客户端存储Token,并且每次发送请求携带Token
  5. 服务端验证Token,并返回数据

3.Token的应用场景

Token有许多应用场景,主要用于身份验证、授权和安全性方面。以下是一些常见的应用场景:

  1. 身份验证和单点登录(SSO):Token用于验证用户身份,避免在每次请求中传递敏感信息如用户名和密码。单点登录允许用户一次登录后访问多个关联的系统而无需重新登录。

  2. API 访问控制:Token可用于控制对API的访问权限。用户在请求API时,需要提供有效的token才能获得访问权限。

  3. 移动应用认证:在移动应用中,token用于验证移动设备和应用程序之间的通信,以确保请求来自合法的源。

  4. 密码重置和临时访问:生成临时token用于密码重置链接,或者为特定操作(如更改邮箱地址)提供临时访问权限。

  5. 用户授权:Token可以用于授予特定权限或访问级别,例如在OAuth授权流程中,授予第三方应用访问资源的权限。

  6. 会话管理:Token可用于管理用户会话,以便在一段时间内保持用户的登录状态。

    等等......

4.Token的使用

项目中使用token实例

首先导入jwt包:

"github.com/golang-jwt/jwt/v5"

接下来先定义一个变量var jwtKey = []byte("a_secret_key")

然后再完成两个函数,分别是 GenerateToken(生成token)和ValidateToken(解析和验证token)函数

func GenerateToken(userID uint) (string, error) {
    // 自定义Token的声明,声明可以理解为一个JSON数据包,包含了我们想要封装在Token里面的信息
    claims := jwt.MapClaims{
        "user_id": userID,
        // exp - 过期时间,格式为Unix时间戳. TODO: set 1 sec for testing
        "exp": time.Now().Add(24 * time.Hour).Unix(),
    }

    // 利用claims生成一个Token
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

    // 使用秘钥来对Token进行签名
    signedToken, err := token.SignedString(jwtKey)
    if err != nil {
        return "", err
    }

    return signedToken, nil
}

这里需要解释一下Claims它是一个JSON对象,包含了我们发送请求所需要的信息,当中包含了我们的请求主体和额外的元数据

func ValidateToken(signedToken string) (uint, error) {
    // 定义一个空的MapClaims,用来保存我们Token中的声明(claims)
    claims := &jwt.MapClaims{}

    // 解析Token,同时将解析出来的claims填入上面声明的空claims,
    // 注意第三个参数是一个函数参数,用来指定解析Token时用什么秘钥
    // 也就是之前定义的jwtKey
    token, err := jwt.ParseWithClaims(
        signedToken,
        claims,
        func(token *jwt.Token) (interface{}, error) {return jwtKey, nil})

    if err != nil || !token.Valid {
        return 0, fmt.Errorf("invalid token")
    }

    // 从解析出来的claims里面提取用户名,并且断言它是字符串类型
    userIDFloat, ok := (*claims)["user_id"].(float64)
    if !ok {
        return 0, fmt.Errorf("Token does not contain user_id")
    }

    userID := uint(userIDFloat)
    return userID, nil
}

这个过程会在所有需要对用户token进行验证的API函数中被执行,它会接受一个token作为输入,然后对该token进行解析和验证,最终输出用户的Id,可以看作是生成token的过程的逆向操作

最后注册并验证中间件

当我们完成关于token的生成和验证函数方法后,需要做的就是写一个中间件tokenMiddleware来调用这些方法,当进行的API工作需要token鉴权时,先通过中间件验证token是否存在以及有效,有效就通过,无效就退回

5.总结

这篇文章记录在学习用token进行API鉴权的过程中运用到的一些知识。希望对你有所帮助,谢谢!