【go商城】gin+mysql实现token登陆校验

2022年6月19日 204点热度 0人点赞 0条评论

Cookie,Session,Token这些用于认证,鉴权的名词相信大家都很熟悉了,网上都有大量的文章讲解,这里我们主要针对本商城通过mysql进行存储的token鉴权进行讲解。

这只是作为一个学习项目使用Mysql进行存储鉴权信息,一般企业项目中的单点登录都会使用redis进行存储

什么是token

访问资源接口(API)时所需要的资源凭证 简单 token 的组成:uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串)

特点

服务端无状态化、可扩展性好 支持移动端设备 安全 支持跨程序调用

token 的身份验证流程:图片token的解释,转自https://juejin.cn/post/6844904034181070861

商城中token存储

新蜂商城项目中存在两个类型的用户:

  1. 后台管理员
  2. 商城用户

其实现逻辑是一致的所以我们调一个讲解即可,这里我们使用后台管理员的登陆进行讲解

我们使用了两张数据库表对用户的登录进行管理

tb_newbee_mall_admin_user & tb_newbee_mall_admin_user_token

我们通过两张表的admin_user_id将 用户和token进行了关联,如果用户登陆状态是有效的,则tb_newbee_mall_admin_user_token中就会存在一条记录,否则就是用户没有登陆。图片

图片
在这里插入图片描述

gin实现接口鉴权

管理员登录的时候,校验用户名和密码,通过的话则将生成的token存入数据库中用于后续的鉴权

// AdminLogin 管理员登陆
func (m *ManageAdminUserService) AdminLogin(params manageReq.MallAdminLoginParam) (err error, mallAdminUser manage.MallAdminUser, adminToken manage.MallAdminUserToken) {
 err = global.GVA_DB.Where("login_user_name=? AND login_password=?", params.UserName, params.PasswordMd5).First(&mallAdminUser).Error
 if mallAdminUser != (manage.MallAdminUser{}) {
  token := getNewToken(time.Now().UnixNano()/1e6int(mallAdminUser.AdminUserId))
  global.GVA_DB.Where("admin_user_id", mallAdminUser.AdminUserId).First(&adminToken)
  nowDate := time.Now()
  // 48小时过期
  expireTime, _ := time.ParseDuration("48h")
  expireDate := nowDate.Add(expireTime)
  // 没有token新增,有token 则更新
  if adminToken == (manage.MallAdminUserToken{}) {
   adminToken.AdminUserId = mallAdminUser.AdminUserId
   adminToken.Token = token
   adminToken.UpdateTime = nowDate
   adminToken.ExpireTime = expireDate
   if err = global.GVA_DB.Create(&adminToken).Error; err != nil {
    return
   }
  } else {
   adminToken.Token = token
   adminToken.UpdateTime = nowDate
   adminToken.ExpireTime = expireDate
   if err = global.GVA_DB.Save(&adminToken).Error; err != nil {
    return
   }
  }
 }
 return err, mallAdminUser, adminToken


}

然后我们定义一个拦截器,让需要鉴权的接口进行token的校验

// 拦截器
func AdminJWTAuth() gin.HandlerFunc {
 return func(c *gin.Context) {
  token := c.Request.Header.Get("token")
  if token == "" {
   response.FailWithDetailed(nil"未登录或非法访问", c)
   c.Abort()
   return
  }
  err, mallAdminUserToken := manageAdminUserTokenService.ExistAdminToken(token)
  if err != nil {
   response.FailWithDetailed(nil"未登录或非法访问", c)
   c.Abort()
   return
  }
  if time.Now().After(mallAdminUserToken.ExpireTime) {
   response.FailWithDetailed(nil"授权已过期", c)
   manageAdminUserTokenService.DeleteMallAdminUserToken(token)
   c.Abort()
   return
  }
  c.Next()
 }


}

最后在我们需要使用鉴权的接口处注册上这个拦截器的中间件,不需要鉴权的接口就不使用拦截器

func (r *ManageAdminUserRouter) InitManageAdminUserRouter(Router *gin.RouterGroup) {
 mallAdminUserRouter := Router.Group("v1").Use(middleware.AdminJWTAuth())
 mallAdminUserWithoutRouter := Router.Group("v1")
 var mallAdminUserApi = v1.ApiGroupApp.ManageApiGroup.ManageAdminUserApi
 {
  mallAdminUserRouter.POST("createMallAdminUser", mallAdminUserApi.CreateAdminUser) // 新建MallAdminUser
  mallAdminUserRouter.PUT("adminUser/name", mallAdminUserApi.UpdateAdminUserName)   // 更新MallAdminUser
  mallAdminUserRouter.PUT("adminUser/password", mallAdminUserApi.UpdateAdminUserPassword)
......
 }
 {
  mallAdminUserWithoutRouter.POST("adminUser/login", mallAdminUserApi.AdminLogin) //管理员登陆
 }
}

因为这里我们没有使用到更高级别的权限管理,go中对于权限管理有casbin这个库,有兴趣的话可以了解一下,这里不做过多的讲解。

效果演示

启动我们后管系统的vue项目,登陆后发现tb_newbee_mall_admin_user_token 表中新增了一条token的数据,同时前端的请求头中也会新增一个token的字段,用于存储鉴权信息。图片

总结

如果你对这一节的内容感兴趣可以访问https://github.com/newbee-ltd/newbee-mall-api-go/ 下载源代码,后续一章会介绍跨域相关的内容

13230【go商城】gin+mysql实现token登陆校验

root

这个人很懒,什么都没留下

文章评论