在go后端加入token验证
什么是token
,"token"指的是一种用于验证用户身份或授权访问的凭证。这种类型的token在进行网络身份验证时非常常见,例如,在网站登录时生成的身份验证令牌或OAuth(开放授权)协议中用于授权访问资源的访问令牌。
token一般在用户登录成功时由服务器端生成并随数据一同发送给客户端,由客户端存储token,并在再次发送请求时,在请求头中带上token并发送给客户端。
为什么要加入token
试想一下,如果没有token,任何游客都可以随意的访问系统内的各个接口,那么系统的安全性就没有办法得到保障。恶意用户可以利用管理员权限,随意调用相关接口以获取系统内部信息,系统用户信息,或者对系统端口进行网络攻击。
加入token以后,我们通过使用token进行授权可以实现细粒度的权限控制,因为每个token可以包含特定的访问权限。这样可以确保用户只能访问其被授权的资源,从而增强系统的安全性。
如何在go项目中部署token
那么,怎么在我们的go项目中部署token呢,当然是利用成熟的go包。
首先在项目中需要导入JWT(JSON Web Token)数据包,
go get github.com/golang-jwt/jwt/v4
然后编写token生成函数
func GenerateJwt() string {
log := logrus.WithFields(logrus.Fields{
"func": "GenerateJwt",
})
token := jwt.New(jwt.SigningMethodHS256)
//jwt.New()创建一个新的JWT对象,使用HS256算法对其进行签名
claims := make(jwt.MapClaims)
claims["exp"] = time.Now().Add(time.Hour * time.Duration(common.TokenDuration)).Unix()
claims["iat"] = time.Now().Unix()
token.Claims = claims
//创建JWT(JSON Web Token)的载荷部分,并声明token的过期事件和创建时间。
tokenString, err := token.SignedString([]byte(common.SecretKey))
//使用密钥对jwt进行签名,并生成toekn字符串
if err != nil {
log.Errorf("GenerateJwt err:%v", err)
}
return tokenString
}
在函数中,使用log记录函数中的错误信息,如果没有记录日志的需求,log也可以省略。
函数中claims用于存储jwt的荷载信息,其中的exp和iat为jwt的标准声明,表示token的过期时间,和创建时间。
common.TokenDuration是一个整形常量,用于设定token存在时间。
common.SecretKey为一个字符串常量,自己设定,表示对数据进行加密时用到的密钥。
由于common.SecretKey只有设定者知道,除系统外,恶意用户将无法对token进行解密。
编写完token函数,在用户登录成功时,应该将token返回给用户,用户以token作为自身身份凭证。
if user.Phone != "" {
if judge := sql.IfadminPhone(c, &user, log); judge {
token := gentoken.GenerateJwt()//token生成函数
c.JSON(200, gin.H{"message": "Login successful", "token": token}) //返回给用户token
return
}}
我们使用postman验证token是否生成成功。
{
"message": "Login successful",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MDkyNTkzMDQsImlhdCI6MTcwOTI1NTcwNH0.zc3DznaTQxOZMqlloS2dSAVC-AgbrE9FId2TQE03_uQ"
}
可以看到,登录成功时服务器成功向用户访问了token
如何验证token
那么,如何验证token信息呢?除了登录和注册功能外,其他所有接口均需验证token信息。
我在项目中使用到了gin框架,使用gin框架的中间件,可以方便的完成这个功能。
func Router() *gin.Engine {
r := gin.Default()
r.POST("/user/login", service.Login)
r.POST("/user/register", service.Register)
auth := r.Group("/")
auth.Use(gentoken.AuthMiddleware())
{
auth.GET("/index", service.GetIndex)
auth.GET("/user/getUserList", service.GetUserList)
auth.GET("/user/findUserByName", service.FindUserByName)
auth.GET("/user/delete", service.DeleteUser) //删除指定用户名的用户
auth.POST("/user/update", service.UpdateUser)
//发送消息
auth.GET("/user/sendUserMsg", service.SendUserMsg)
auth.GET("/user/sendMsg", service.SendMsg)
}}
通过r.Group将除登录注册外的所有功能设置为一个auth组,并为该组成员添加中间件gentoken.AuthMiddleware()函数。
这样,所有要访问auth组的请求都需要经过AuthMiddleware()函数验证后才能获取到服务。
在AuthMiddleware()函数中我们添加验证token的请求:
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
tokenString := c.GetHeader("Authorization")
if tokenString == "" {
c.AbortWithStatus(http.StatusUnauthorized)
return
}
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
return []byte(common.SecretKey), nil
})
if err == nil && token.Valid {
c.Next()
} else {
c.AbortWithStatus(http.StatusUnauthorized)
}
}
}
其中common.SecretKey为加密时使用的密钥,此时要通过jwt.Parse()函数将其解密。
通过token.Valid验证token是否过期,是否为系统签发。
好了,现在token验证机制已经完成。
验证
我们首先用postman发送不带token的请求到系统服务。
发现系统无返回值。
在头部带上token后:
成功使用系统功能获取到用户信息。
好了,现在你可以在自己的项目里部署一个简单的token来进行用户身份验证啦!!