在阅读了官方给定的API文档之后,我发现绝大多数的API请求都必须带上用户鉴权token,之前接触过但是没有仔细研究,正好通过这次机会好好学习一下
Token
1.什么是Token
当谈到“token”,我们指的是一种称为“令牌”的概念。在服务器与客户端交互中,它是由服务端生成的一串字符串,具有特殊意义,用于识别和验证客户端的请求。
一旦用户首次登录,服务器会创造一个独特的token,并将其发送给客户端。以后,客户端只需在请求数据时携带这个token,无需再提供用户名和密码。
这个token通常由几部分构成:首先是用户唯一身份标识(称为uid),用于确认用户的身份。接着是当前时间的时间戳,确保token的时效性。最后,为了加强安全性,token的前几位会经过哈希算法处理,压缩成一个固定长度的十六进制字符串,也被称为签名。这个签名的存在有助于防止token被泄露所带来的风险。
2.Token的原理
- 用户通过用户名和密码发送请求
- 程序校验
- 程序返回一个Token给客户端
- 客户端存储Token,并且每次发送请求携带Token
- 服务端验证Token,并返回数据
3.Token的应用场景
Token有许多应用场景,主要用于身份验证、授权和安全性方面。以下是一些常见的应用场景:
-
身份验证和单点登录(SSO):Token用于验证用户身份,避免在每次请求中传递敏感信息如用户名和密码。单点登录允许用户一次登录后访问多个关联的系统而无需重新登录。
-
API 访问控制:Token可用于控制对API的访问权限。用户在请求API时,需要提供有效的token才能获得访问权限。
-
移动应用认证:在移动应用中,token用于验证移动设备和应用程序之间的通信,以确保请求来自合法的源。
-
密码重置和临时访问:生成临时token用于密码重置链接,或者为特定操作(如更改邮箱地址)提供临时访问权限。
-
用户授权:Token可以用于授予特定权限或访问级别,例如在OAuth授权流程中,授予第三方应用访问资源的权限。
-
会话管理: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鉴权的过程中运用到的一些知识。希望对你有所帮助,谢谢!