Go 中实现 JWT 登录 | 臭大佬
简介
Go 中实现 JWT 登录
什么是JWT
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
相信很多朋友在写后台接口的时候都有用过,最近想把博客的后端用 beego
框架来实现,而后台模块接口都是需要登录后才能访问的,这就需要用的JWT
了,go
中相应的包有github.com/dgrijalva/jwt-go
,下面简单介绍一下实现过程。
本文是在 beego
框架下实现的,如果您用的不是beego
框架,逻辑是差不多的,请根据具体情况修改代码。
安装扩展
执行命令:
go get github.com/dgrijalva/jwt-go
除了JWT
包,这里再推荐一个包github.com/syyongx/php2go
,这个包让go
代码敲起来像php
,包里面实现了很多类似于php
函数的方法,对于php
程序员可是福音啊,敲起代码一把梭。墙裂
推荐。
go get github.com/syyongx/php2go
实现过程
我在 mian.go
的init方法中引入了中间件方法,
middlewares.Init()
中实现了过滤器功能,当路由进来首先会去判断是否匹配正则表达式”/api/*”,
如果匹配成功,会去判断是否在开放路由数组中。不在的话去验证token
,验证成功则可以返回数据,否则无法获取数据。从未实现登录验证逻辑。
生成 token
生成token
是在用户登录的时候,通过验证账号密码是否正确进行发放token。
import (
...
"github.com/dgrijalva/jwt-go"
)
//用户登录
func (self *AdminController) Login() {
// 用户账号密码验证逻辑
...
// 带权限创建令牌
claims := make(jwt.MapClaims)
claims["account"] = admin.Account
claims["username"] = admin.Username
claims["tel"] = admin.Tel
claims["email"] = admin.Email
claims["exp"] = time.Now().Add(time.Hour * 2).Unix() //2小时有效期,过期需要重新登录获取token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// 使用自定义字符串加密 and get the complete encoded token as a string
tokenString, err := token.SignedString([]byte("mykey"))
if err != nil {
return
}
jsonData := make(map[string]interface{}, 4)
jsonData["token"] = tokenString
jsonData["id"] = admin.Id
jsonData["account"] = admin.Account
jsonData["username"] = admin.Username
jsonData["tel"] = admin.Tel
jsonData["email"] = admin.Email
// 返回带token的数据
self.ResJson(0, "获取成功", jsonData, nil)
}
调用
helper := commons.Helper{}
token, e := helper.ParseToken(ctx) // ctx *context.Context
if e != nil {
return
}
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
// 验证失败
return
}
验证 token
/**
* Description:
* User: Vijay <1937832819@qq.com>
* Date: 2020/08/21
* Time: 17:40
*/
package commons
import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/context"
"github.com/dgrijalva/jwt-go"
"strings"
)
type Helper struct {
}
/**
wjt token 验证
*/
func (h *Helper) ParseToken(ctx *context.Context) (t *jwt.Token, e interface{}) {
authString := ctx.Input.Header("Authorization")
kv := strings.Split(authString, " ")
if len(kv) != 2 || kv[0] != "Bearer" {
return nil, "AuthString无效"
}
tokenString := kv[1]
// Parse token
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
return []byte("mykey"), nil
})
if err != nil {
if ve, ok := err.(*jwt.ValidationError); ok {
if ve.Errors&jwt.ValidationErrorMalformed != 0 {
// That's not even a token
return nil, err
} else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 {
// Token is either expired or not active yet
return nil, "令牌已过期或尚未激活"
} else {
// Couldn't handle this token
return nil, "无法处理此令牌"
}
} else {
// Couldn't handle this token
return nil, "无法处理此令牌"
}
}
if !token.Valid {
return nil, "令牌无效"
}
return token, nil
}
验证通过:
验证失败时:
刚接触go
不久,实现有点lou,大神勿喷,如果有错误或者有其他优化方案,希望大神们给小弟补补课,我很乐意接受批评,互相学习。