说明
插件地址 https://github.com/gogf/gf-jwt
gf-jwt是gf框架的jwt 中间件
, 再次强调gf-jwt
是一个中间件
gf-jwt插件是鹏哥
根据 gin-jwt
的设计灵感来开发的
gf-jwt插件是基于go-jwt
开发的
使用说明
由于github中的说明文档对新手不太友好,新手一般无从下手。所以本篇文章就以最简单的方式向大家介绍这个插件的使用方法
刘二狗:怎么生成token ?
答: gf-jwt已经封装好了,不用你自己动手来生成
s.BindHandler("POST:/login", auth.GfJWTMiddleware.LoginHandler)
请求返回:
{
"code": 200,
"expire": "2020-01-08T11:16:41+08:00",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Nzg0NTM0MDEsImlkIjoiYWRtaW4iLCJvcmlnX2lhdCI6MTU3ODQ1MzEwMSwidXNlcm5hbWUiOiJhZG1pbiJ9.YwigtrdlUDHYYRpd9aOu-FlheQM2IaYkNLLG-qA4L4o"
}
张木棍:那我想自己定义返回的视图函数咋搞?
答:生成token、刷新token、验证token......gf-jwt中都已经封装好了,想自定义的话也很简单, 只需自己定义指定函数,配置一下即可
// 定义自定义中间件
var CustomGfJWTMiddleware *jwt.GfJWTMiddleware
// 重写该方法
func init () {
// 重新定义GfJWTMiddleware
authMiddleware, err := jwt.New(&jwt.GfJWTMiddleware{
Realm: "test zone", // 用于展示中间件的名称
Key: []byte("secret key"), // 密钥
Timeout: time.Minute * 5, // token过期时间
MaxRefresh: time.Minute * 5,
IdentityKey: "id", // 身份验证的key值
TokenLookup: "header: Authorization, query: token, cookie: jwt", // token检索模式,用于提取token-> Authorization
TokenHeadName: "Bearer", // token在请求头时的名称,默认值为Bearer
// 客户端在header中传入Authorization 对一个值是Bearer + 空格 + token
TimeFunc: time.Now, // 测试或服务器在其他时区可设置该属性
Authenticator: Authenticator, // 根据登录信息对用户进行身份验证的回调函数
LoginResponse: LoginResponse, // 完成登录后返回的信息,用户可自定义返回数据,默认返回
RefreshResponse: auth.RefreshResponse, // 刷新token后返回的信息,用户可自定义返回数据,默认返回
Unauthorized: auth.Unauthorized, // 处理不进行授权的逻辑
IdentityHandler: auth.IdentityHandler, // 解析并设置用户身份信息
PayloadFunc: auth.PayloadFunc, // 登录期间的回调的函数
})
if err != nil {
glog.Fatal("JWT Error:" + err.Error())
}
CustomGfJWTMiddleware = authMiddleware
}
王大宝: 配置好了咋个使用嘞?
答: 首先定义中间件,中间件中使用自己重写的CustomGfJWTMiddleware
// 自定义中间件
func MiddlewareAuth(r *ghttp.Request) {
// 使用 gf-jwt中间件
CustomGfJWTMiddleware.MiddlewareFunc()(r)
r.Middleware.Next()
}
然后在视图函数中使用就好了
// 使用中间件
s.Group("/api", func(group *ghttp.RouterGroup) {
// 使用中间件
group.Middleware(MiddlewareAuth)
// 需要验证token的视图函数
group.GET("/get_info", func(r *ghttp.Request) {
r.Response.Write("api get_info...")
})
// 刷新token
group.POST("/refresh_token", CustomGfJWTMiddleware.RefreshHandler)
})
啸天犬:完整代码拿来看看
答:好
package main
import (
"gfjwttest/auth"
jwt "github.com/gogf/gf-jwt"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
"github.com/gogf/gf/os/glog"
"github.com/gogf/gf/util/gvalid"
"net/http"
"time"
)
// 定义自定义中间件
var CustomGfJWTMiddleware *jwt.GfJWTMiddleware
// 重写该方法
func init () {
// 重新定义GfJWTMiddleware
authMiddleware, err := jwt.New(&jwt.GfJWTMiddleware{
Realm: "test zone", // 用于展示中间件的名称
Key: []byte("secret key"), // 密钥
Timeout: time.Minute * 5, // token过期时间
MaxRefresh: time.Minute * 5,
IdentityKey: "id", // 身份验证的key值
TokenLookup: "header: Authorization, query: token, cookie: jwt", // token检索模式,用于提取token-> Authorization
TokenHeadName: "Bearer", // token在请求头时的名称,默认值为Bearer
// 客户端在header中传入Authorization 对一个值是Bearer + 空格 + token
TimeFunc: time.Now, // 测试或服务器在其他时区可设置该属性
Authenticator: Authenticator, // 根据登录信息对用户进行身份验证的回调函数
LoginResponse: LoginResponse, // 完成登录后返回的信息,用户可自定义返回数据,默认返回
RefreshResponse: auth.RefreshResponse, // 刷新token后返回的信息,用户可自定义返回数据,默认返回
Unauthorized: auth.Unauthorized, // 处理不进行授权的逻辑
IdentityHandler: auth.IdentityHandler, // 解析并设置用户身份信息
PayloadFunc: auth.PayloadFunc, // 登录期间的回调的函数
})
if err != nil {
glog.Fatal("JWT Error:" + err.Error())
}
CustomGfJWTMiddleware = authMiddleware
}
// 自定义中间件
func MiddlewareAuth(r *ghttp.Request) {
// 使用 gf-jwt中间件
CustomGfJWTMiddleware.MiddlewareFunc()(r)
r.Middleware.Next()
}
func main() {
s := g.Server()
// 登录,返回token
s.BindHandler("POST:/login", CustomGfJWTMiddleware.LoginHandler)
// 使用中间件
s.Group("/api", func(group *ghttp.RouterGroup) {
// 使用中间件
group.Middleware(MiddlewareAuth)
// 需要验证token的视图函数
group.GET("/get_info", func(r *ghttp.Request) {
r.Response.Write("api get_info...")
})
// 刷新token
group.POST("/refresh_token", CustomGfJWTMiddleware.RefreshHandler)
})
s.Run()
}
//身份验证器用于验证登录参数。
//它必须返回用户数据作为用户标识符,它将存储在声明数组中。
//检查错误(e)以确定适当的错误消息。
func Authenticator(r *ghttp.Request) (interface{}, error) {
data := r.GetMap()
if e := gvalid.CheckMap(data, auth.ValidationRules); e != nil {
return "", jwt.ErrFailedAuthentication
}
if data["username"] == "admin" && data["password"] == "111111" {
return g.Map {
"username": data["username"],
"id": 1,
}, nil
}
return nil, jwt.ErrFailedAuthentication
}
// LoginResponse用于定义自定义的登录成功回调函数。
func LoginResponse(r *ghttp.Request, code int, token string, expire time.Time) {
_ = r.Response.WriteJson(g.Map{
"id": 1,
"code": http.StatusOK,
"token": token,
"expire": expire.Format(time.RFC3339),
})
r.ExitAll()
}
胖虎:客户端请求一个我看看
答:好
李富贵:请求一下数据接口我看看(登录后的)
答:行吧, 记得把刚才请求的token加载请求头中
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Nzg0NTQ1MDAsImlkIjoxLCJvcmlnX2lhdCI6MTU3ODQ1NDIwMCwidXNlcm5hbWUiOiJhZG1pbiJ9.EOmHjtSS2NVNJzMyyAXfQ0CtlX0zg0laQJGkxI8wN3M
刘碧萝:能给我小心心吗?
答:不能,滚!
刘碧萝:好嘞