gtoken基于 gf 框架的 token 插件

联合创作 · 2023-09-30 19:57

gtoken

介绍

基于GoFrame框架的token插件,通过服务端验证方式实现token认证;已完全可以支撑线上token认证,通过Redis支持集群模式;使用简单,大家可以放心使用;

gtoken优势

  1. gtoken支撑单点应用使用内存存储,也支持集群使用redis存储;完全适用于企业生产级使用;

  2. 有效的避免了jwt服务端无法退出问题;

  3. 解决jwt无法作废已颁布的令牌,只能等到令牌过期问题;

  4. 通过用户扩展信息存储在服务端,有效规避了jwt携带大量用户扩展信息导致降低传输效率问题;

  5. 有效避免jwt需要客户端实现续签功能,增加客户端复杂度;支持服务端自动续期,客户端不需要关心续签逻辑;

特性说明

  1. 支持token认证,不强依赖于session和cookie,适用jwt和session认证所有场景;

  2. 支持单机gcache和集群gredis模式;

# 缓存模式 1 gcache 2 gredis
CacheMode = 2
  1. 支持服务端缓存自动续期功能

// 注:通过MaxRefresh,默认当用户第五天访问时,自动续期
// 超时时间 默认10天
Timeout int
// 缓存刷新时间 默认为超时时间的一半
MaxRefresh int
  1. 支持分组拦截、全局拦截、深度路径拦截,便于根据个人需求定制拦截器;建议使用分组拦截方式;

  2. 框架使用简单,只需要设置登录验证方法以及登录、登出路径即可;

  3. gtoken v1.4.0版本开始支持分组中间件方式实现,但依然兼容全局和深度中间件实现方式;

安装教程

  • gopath模式: go get github.com/goflyfox/gtoken

  • 或者 使用go.mod添加 :require github.com/goflyfox/gtoken latest

分组中间件实现

GoFrame官方推荐使用Group方式实现路由和中间件;

使用说明

推荐使用分组方式实现

    // 启动gtoken
    gfToken := &gtoken.GfToken{
        LoginPath:        "/login",
        LoginBeforeFunc:  loginFunc,
        LogoutPath:       "/user/logout",
    }
    s.Group("/", func(group *ghttp.RouterGroup) {
        group.Middleware(CORS)
        gfToken.Middleware(group)

        group.ALL("/system/user", func(r *ghttp.Request) {
            r.Response.WriteJson(gtoken.Succ("system user"))
        })
        ………………
    })

登录方法实现,通过username返回空或者r.ExitAll()\r.Exit()处理认证失败;

func Login(r *ghttp.Request) (string, interface{}) {
    username := r.GetPostString("username")
    passwd := r.GetPostString("passwd")

    // TODO 进行登录校验
    if username == "" || passwd == "" {
        r.Response.WriteJson(gtoken.Fail("账号或密码错误."))
        r.ExitAll()
    }

    return username, ""
}

通过gtoken.GetTokenData(r)获取登录信息

路径拦截规则

    AuthExcludePaths: g.SliceStr{"/user/info", "/system/user/*"}, // 不拦截路径  /user/info,/system/user/info,/system/user,
  1. 分组中间件实现,不需要设置AuthPaths认证路径,设置也没有作用,需要认证路径为该分组下所有路由

  2. 使用分组拦截的是通过GoFrame的group.Middleware(authMiddleware)方法,对该分组下的所有路由进行拦截;

  3. 对登录接口路径loginPath做拦截认证放行;

  4. 严格按照GoFrame分组中间件拦截优先级;如果使用跨域中间件,建议放在跨域中间件之后;

  5. 如果配置AuthExcludePaths路径,会将配置的不拦截路径排除;

逻辑测试

参考sample项目,先运行main.go,然后可运行api_test.go进行测试并查看结果;验证逻辑说明:

  1. 访问用户信息,提示未携带token

  2. 调用登录后,携带token访问正常

  3. 调用登出提示成功

  4. 携带之前token访问,提示未登录

=== RUN   TestAdminSystemUser
    api_admin_test.go:22: 1. not login and visit user
    api_admin_test.go:29: {"code":-401,"msg":"请求错误或登录超时","data":""}
    api_admin_test.go:42: 2. execute login and visit user
    api_admin_test.go:45: {"code":0,"msg":"success","data":"system user"}
    api_admin_test.go:51: 3. execute logout
    api_admin_test.go:54: {"code":0,"msg":"success","data":"Logout success"}
    api_admin_test.go:60: 4. visit user
    api_admin_test.go:65: {"code":-401,"msg":"请求错误或登录超时","data":""}

全局中间件实现

使用说明

只需要配置登录路径、登出路径、拦截路径以及登录校验实现即可

    // 启动gtoken
    gtoken := &gtoken.GfToken{
        LoginPath:       "/login",
        LoginBeforeFunc: loginFunc,
        LogoutPath:      "/user/logout",
        AuthPaths:        g.SliceStr{"/user", "/system"}, // 这里是按照前缀拦截,拦截/user /user/list /user/add ...
        GlobalMiddleware: true,                           // 开启全局拦截,默认关闭
    }
    gtoken.Start()

登录方法实现,通过username返回空或者r.ExitAll()\r.Exit()处理认证失败;

func Login(r *ghttp.Request) (string, interface{}) {
    username := r.GetPostString("username")
    passwd := r.GetPostString("passwd")

    // TODO 进行登录校验
    if username == "" || passwd == "" {
        r.Response.WriteJson(gtoken.Fail("账号或密码错误."))
        r.ExitAll()
    }

    return username, ""
}

通过gtoken.GetTokenData(r)获取登录信息

路径拦截规则

    AuthPaths:        g.SliceStr{"/user", "/system"},             // 这里是按照前缀拦截,拦截/user /user/list /user/add ...
    AuthExcludePaths: g.SliceStr{"/user/info", "/system/user/*"}, // 不拦截路径  /user/info,/system/user/info,/system/user,
    GlobalMiddleware: true,                           // 开启全局拦截,默认关闭
  1. GlobalMiddleware:true全局拦截的是通过GF的BindMiddleware方法创建拦截/*

  2. GlobalMiddleware:false路径拦截的是通过GF的BindMiddleware方法创建拦截/user*和/system/*

  3. 按照中间件优先级路径拦截优先级很高;如果先实现部分中间件在认证前处理需要切换成全局拦截器,严格按照注册顺序即可;

  4. 程序先处理认证路径,如果满足;再排除不拦截路径;

  5. 如果只想用排除路径功能,将拦截路径设置为/*即可;

逻辑测试

参考sample1项目,先运行main.go,然后可运行api_test.go进行测试并查看结果;验证逻辑说明:

  1. 访问用户信息,提示未携带token

  2. 调用登录后,携带token访问正常

  3. 调用登出提示成功

  4. 携带之前token访问,提示未登录

=== RUN   TestSystemUser
    api_test.go:43: 1. not login and visit user
    api_test.go:50: {"code":-401,"msg":"请求错误或登录超时","data":""}
    api_test.go:63: 2. execute login and visit user
    api_test.go:66: {"code":0,"msg":"success","data":"system user"}
    api_test.go:72: 3. execute logout
    api_test.go:75: {"code":0,"msg":"success","data":"Logout success"}
    api_test.go:81: 4. visit user
    api_test.go:86: {"code":-401,"msg":"请求错误或登录超时","data":""}

返回码及配置项

  1. 正常操作成功返回0

  2. 未登录访问需要登录资源返回401

  3. 程序异常返回-99,如编解码错误等

SUCCESS      = 0  // 正常
FAIL         = -1  // 失败
ERROR        = -99  // 异常
UNAUTHORIZED = -401  // 未认证

配置项说明

具体可参考GfToken结构体,字段解释如下:

名称 配置字段 说明 分组中间件 全局中间件
服务名 ServerName 默认空即可 支持 支持
缓存模式 CacheMode 1 gcache 2 gredis 默认1 支持 支持
缓存key CacheKey 默认缓存前缀GToken: 支持 支持
超时时间 Timeout 默认10天(毫秒) 支持 支持
缓存刷新时间 MaxRefresh 默认为超时时间的一半(毫秒) 支持 支持
Token分隔符 TokenDelimiter 默认_ 支持 支持
Token加密key EncryptKey 默认12345678912345678912345678912345 支持 支持
认证失败提示 AuthFailMsg 默认请求错误或登录超时 支持 支持
是否支持多端登录 MultiLogin 默认false 支持 支持
中间件类型 MiddlewareType 1、Group 2、Bind 3 、Global; 使用分组模式不需要设置 支持 支持
登录路径 LoginPath 登录接口路径 支持 支持
登录验证方法 LoginBeforeFunc 登录验证需要用户实现方法 支持 支持
登录返回方法 LoginAfterFunc 登录完成后调用 支持 支持
登出地址 LogoutPath 登出接口路径 支持 支持
登出验证方法 LogoutBeforeFunc 登出接口前调用 支持 支持
登出返回方法 LogoutAfterFunc 登出接口完成后调用 支持 支持
拦截地址 AuthPaths 此路径列表进行认证 不需要 支持
拦截排除地址 AuthExcludePaths 此路径列表不进行认证 支持 支持
认证验证方法 AuthBeforeFunc 拦截认证前后调用 支持 支持
认证返回方法 AuthAfterFunc 拦截认证完成后调用 支持 支持

感谢

  1. gf框架 https://github.com/gogf/gf

浏览 13
点赞
评论
收藏
分享

手机扫一扫分享

编辑 分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

编辑 分享
举报