前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Beego JWT 鉴权

Beego JWT 鉴权

作者头像
会呼吸的Coder
发布2020-02-17 17:31:59
3.7K0
发布2020-02-17 17:31:59
举报
文章被收录于专栏:会呼吸的Coder会呼吸的Coder

简介

谈起web应用,登录鉴权是必不可少的一步。beego应用当然也需要鉴权。今天我结合我目前在做的项目谈一下jwt鉴权。

首先大家应该要知道JWT是什么

JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。

使用场景

Authorization (授权) :这是使用JWT的最常见场景。一旦用户登录,后续每个请求都将包含JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录是现在广泛使用的JWT的一个特性,因为它的开销很小,并且可以轻松地跨域使用。

Information Exchange (信息交换) :对于安全的在各方之间传输信息而言,JSON Web Tokens无疑是一种很好的方式。因为JWTs可以被签名,例如,用公钥/私钥对,你可以确定发送人就是它们所说的那个人。另外,由于签名是使用头和有效负载计算的,您还可以验证内容没有被篡改。

工具包

GO语言使用JWT,比较常用的是JWT-go 和JWT-Auth

其下载命令分别如下:

代码语言:javascript
复制
go get github.com/dgrijalva/jwt-go
go get github.com/adam-hanna/jwt-auth

因为我是利用jwt-go鉴权的,所以也接下来只讲诉jwt-go的应用,所有代码copy后就能使用。

代码

首先创建一个tokenUtil.go 文件,主要是处理一些token的操作。这里面有三个函数。

创建token

这一步主要是在用户登录的时候,如果用户名密码正确,调用此方法,生成相应的token,返回给用户

代码语言:javascript
复制
func CreateToken(Phone string) string {
  token := jwt.New(jwt.SigningMethodHS256)
  claims :=make(jwt.MapClaims)
  tokenexp,_ :=strconv.Atoi(beego.AppConfig.String("Tokenexp"))
  claims["exp"]=time.Now().Add(time.Hour * time.Duration(tokenexp)).Unix()
  claims["iat"] =time.Now().Unix()
  claims["phone"]=Phone
  token.Claims=claims
  tokenString,_ :=token.SignedString([]byte(beego.AppConfig.String("TokenSecrets")))
  return tokenString
}

我这边使用手机号去登录的,手机号是唯一的,所以我利用手机号创建的token。

检验token

这一步主要是每次用户访问项目接口,检查一下是否携带了token字段,如果携带了,则解析获取相应的用户名,然后查看是否有相应的权限。

代码语言:javascript
复制
func CheckToken(tokenString string) string {
  Phone :=""
  token,_ :=jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
    if _,ok :=token.Method.(*jwt.SigningMethodHMAC); !ok {
      return nil,fmt.Errorf("Unexpected signing method")
    }
    return []byte(beego.AppConfig.String("TokenSecrets")),nil
  })
  claims,_:=token.Claims.(jwt.MapClaims)
  Phone =claims["phone"].(string)
  return Phone
}

当然了真正的项目中不会这么简单的鉴权,现在的方式。只要有人能拿到token。然后完全可以畅通无阻的用任何脚本去访问。

登录认证模块

代码语言:javascript
复制
func AuthenticateUserForLogin(loginName,password string)(*models.AdminUser,error){
  if len(password) ==0 || len(loginName)==0 {
    return nil,errors.New("Error:用户或者密码为空")
  }
  data :=[]byte(password)
  has :=md5.Sum(data)
  password =fmt.Sprintf("%x",has)
  v,err:=models.GetAdminUserByPhone(loginName) //数据库查询语句。自己写的
  fmt.Println(v)

  if err !=nil {
    return nil,errors.New("Error:未找到该用户")

  }else if v.Password!=password {
    return nil,errors.New("Error:密码错误")

  }else{
    return v,nil
  }
}

我这边只是简单的md5加密了一下密码,然后根据手机号去查询用户,查询得到后判断一下密码是否一致,如果一致,则返回用户和token。

model模块

我是用bee工具创建的model,因为在创建的时候生成的查询语句只是根据id去查询的,所以,我写了一个根据手机号查询的用户的函数。(如果大家不懂bee工具,可以看看我之前的文章,或者百度一下)

代码语言:javascript
复制
func GetAdminUserByPhone(phone string)(v *AdminUser,err error){
  o :=orm.NewOrm()
  v =&AdminUser{} //数据库模型
  v.Phone=phone //将要查询的字段赋值
  if err =o.Read(v,"Phone"); err==nil {  //o.Read() 方法第一个是模型,第二个开始是要查询的字段,多个字段则用逗号隔开就好了,比如 (“字段1”,“字段二”)
    return v,nil
  }
  return nil,err
}

这个实际做的时候要根据自己的数据库灵活发挥,

controller 模块

这里我做了一下登录的操作

代码语言:javascript
复制
func(c *AdminUserController) Login(){
  var v models.AdminUser
  //读取解析json数据并复制给AdminUser
  err :=json.Unmarshal(c.Ctx.Input.RequestBody,&v)
  if err !=nil {
    fmt.Println("json Unmarshal error:",err.Error())
  }
  login_name :=v.UserName
  password :=v.Password
  //登录检验
  user,err :=utils.AuthenticateUserForLogin(login_name,password)
  if user ==nil {
    c.Data["json"]=map[string]interface{}{"success": -1, "message": err}
    c.ServeJSON()
    return
  }
  //创建token
  tokenString :=utils.CreateToken(login_name)
  c.Ctx.Output.Header("TOKEN",tokenString)
  c.Ctx.SetCookie("token",tokenString,"3600","/")
  c.Ctx.SetCookie("USERID",user.Phone,"3600","/")
  c.Data["json"]=map[string]interface{}{"success":0, "msg": "登录成功", "user": user}
  c.ServeJSON()
}

同时我们要在router配置路由,由于我这个是bee api生成的项目,所以就比着葫芦画瓢,做了一下路由配置,这个配置在router里面,如果你不是bee api项目,路由配置可能不一样,这个也可以百度一下,不是很难。网上抄一下就好了。

在当前controller文件中,首先要将这个函数访问URLMapping中。

代码语言:javascript
复制
func (c *AdminUserController) URLMapping() {
  c.Mapping("Post", c.Post)
  c.Mapping("GetOne", c.GetOne)
  c.Mapping("GetAll", c.GetAll)
  c.Mapping("Put", c.Put)
  c.Mapping("Delete", c.Delete)
  c.Mapping("Login", c.Login) //这就是创建的登录接口
}

然后在router下配置,根据map去取值。

代码语言:javascript
复制
beego.GlobalControllerRouter["nuoAdmin/controllers:AdminUserController"] = append(beego.GlobalControllerRouter["nuoAdmin/controllers:AdminUserController"],
        beego.ControllerComments{
            Method: "Login", 
            Router: `/Login`,
            AllowHTTPMethods: []string{"post"},
            MethodParams: param.Make(),
            Filters: nil,
            Params: nil})

现在我们可以访问请求试一下。

成功的拿到了token,然后我们试一下访问其他接口

接下来我们做一下中间件,拦截一下所有不携带token的请求。

在router.go文件中,添加:

代码语言:javascript
复制

beego.InsertFilter("*",beego.BeforeRouter,cors.Allow(&cors.Options{
   AllowAllOrigins:true,
   AllowMethods:[]string{"GET","POST","PUT","DELETE","OPTION"},
   AllowHeaders:     []string{"Origin", "Authorization", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type"},
   ExposeHeaders:    []string{"Content-Length", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type"},
   AllowCredentials: true,
}))
beego.InsertFilter("/*",beego.BeforeRouter, func(context *context.Context) {
   if context.Request.RequestURI !="/v1/admin_user/Login" {
      //此处可以校验一下ip,设备等
      cookie,err :=context.Request.Cookie("token")
      fmt.Print(strings.Index(context.Request.RequestURI,"/v1/admin_user/Login"))
      if strings.Index(context.Request.RequestURI,"/v1/admin_user/Login")>=0 || strings.Index(context.Request.RequestURI,"/static")>=0 {

      }else if err !=nil || utils.CheckToken(cookie.Value)=="" {
        context.ResponseWriter.Write([]byte("您无权访问"))
      }
   }
})
//此处上面的是要添加的字段
beego.AddNamespace(ns)

InsertFilter方法第一个是拦截的路由,我是将所有的路由都进行了拦截的,大家到时候也可以根据实际情况只拦截需要的路由,我现在这样写,同样把登录请求拦截了,这时候每次请求登录也会进行校验,但是登录是没有token的所以,我在这里做了一个判断,如果是登录接口,则不进行判断校验。

这时候再访问其他接口,则会如下图所示:

自此,一个简单的登录鉴权做完了。是不是很简单。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-09-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 初级程序员 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
消息队列 TDMQ
消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档