| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523 |
- package gtoken
- import (
- "dashoo.cn/opms_libary/utils"
- "strings"
- "github.com/gogf/gf/crypto/gaes"
- "github.com/gogf/gf/crypto/gmd5"
- "github.com/gogf/gf/encoding/gbase64"
- "github.com/gogf/gf/frame/g"
- "github.com/gogf/gf/net/ghttp"
- "github.com/gogf/gf/os/glog"
- "github.com/gogf/gf/os/gtime"
- "github.com/gogf/gf/text/gstr"
- "github.com/gogf/gf/util/gconv"
- "github.com/gogf/gf/util/grand"
- )
- const (
- CacheModeCache = 1
- CacheModeRedis = 2
- )
- var GFToken *GfToken
- // GfToken gtoken结构体
- type GfToken struct {
- // 缓存模式 1 gcache 2 gredis 默认1
- CacheMode int8
- // 缓存key
- CacheKey string
- // 超时时间 默认10天
- Timeout int
- // 缓存刷新时间 默认为超时时间的一半
- MaxRefresh int
- // Token分隔符
- TokenDelimiter string
- // Token加密key
- EncryptKey []byte
- // 认证失败中文提示
- AuthFailMsg string
- // 是否支持多端登录,默认false
- MultiLogin bool
- // 登录路径
- LoginPath string
- // 登录验证方法 return userKey 用户标识 如果userKey为空,结束执行
- LoginBeforeFunc func(r *ghttp.Request) (string, interface{})
- // 登录返回方法
- LoginAfterFunc func(r *ghttp.Request, respData Resp)
- // 登出地址
- LogoutPath string
- // 登出验证方法 return true 继续执行,否则结束执行
- LogoutBeforeFunc func(r *ghttp.Request) bool
- // 登出返回方法
- LogoutAfterFunc func(r *ghttp.Request, respData Resp)
- // 拦截地址
- AuthPaths g.SliceStr
- // 认证验证方法 return true 继续执行,否则结束执行
- AuthBeforeFunc func(r *ghttp.Request) bool
- // 认证返回方法
- AuthAfterFunc func(r *ghttp.Request, respData Resp)
- }
- // Init 初始化
- func (m *GfToken) Init() bool {
- if m.CacheMode == 0 {
- m.CacheMode = CacheModeCache
- }
- if m.CacheKey == "" {
- m.CacheKey = "GToken:"
- }
- if m.Timeout == 0 {
- m.Timeout = 10 * 24 * 60 * 60 * 1000
- }
- if m.MaxRefresh == 0 {
- m.MaxRefresh = m.Timeout / 2
- }
- if m.TokenDelimiter == "" {
- m.TokenDelimiter = "_"
- }
- if len(m.EncryptKey) == 0 {
- m.EncryptKey = []byte("12345678912345678912345678912345")
- }
- if m.AuthFailMsg == "" {
- m.AuthFailMsg = "请求错误或登录超时"
- }
- //if m.LoginAfterFunc == nil {
- // m.LoginAfterFunc = func(r *ghttp.Request, respData Resp) {
- // if !respData.Success() {
- // r.Response.WriteJson(respData)
- // } else {
- // r.Response.WriteJson(Succ(g.Map{
- // "token": respData.GetString("token"),
- // }))
- // }
- // }
- //}
- //
- //if m.LogoutBeforeFunc == nil {
- // m.LogoutBeforeFunc = func(r *ghttp.Request) bool {
- // return true
- // }
- //}
- //
- //if m.LogoutAfterFunc == nil {
- // m.LogoutAfterFunc = func(r *ghttp.Request, respData Resp) {
- // if respData.Success() {
- // r.Response.WriteJson(Succ("Logout success"))
- // } else {
- // r.Response.WriteJson(respData)
- // }
- // }
- //}
- //
- //if m.AuthBeforeFunc == nil {
- // m.AuthBeforeFunc = func(r *ghttp.Request) bool {
- // // 静态页面不拦截
- // if r.IsFileRequest() {
- // return false
- // }
- //
- // return true
- // }
- //}
- //if m.AuthAfterFunc == nil {
- // m.AuthAfterFunc = func(r *ghttp.Request, respData Resp) {
- // if respData.Success() {
- // r.Middleware.Next()
- // } else {
- // var params map[string]interface{}
- // if r.Method == "GET" {
- // params = r.GetMap()
- // } else if r.Method == "POST" {
- // params = r.GetMap()
- // } else {
- // r.Response.Writeln("Request Method is ERROR! ")
- // return
- // }
- //
- // no := gconv.String(gtime.TimestampMilli())
- //
- // glog.Info(fmt.Sprintf("[AUTH_%s][url:%s][params:%s][data:%s]",
- // no, r.URL.Path, params, respData.Json()))
- // respData.Msg = m.AuthFailMsg
- // r.Response.WriteJson(respData)
- // r.ExitAll()
- // }
- // }
- //}
- return true
- }
- // Start 启动
- func (m *GfToken) Start() bool {
- if !m.Init() {
- return false
- }
- glog.Info("[GToken][params:" + m.String() + "]start... ")
- //s := g.Server()
- // 缓存模式
- if m.CacheMode > CacheModeRedis {
- glog.Error("[GToken]CacheMode set error")
- return false
- }
- // 认证拦截器
- //if m.AuthPaths == nil {
- // glog.Error("[GToken]HookPathList not set")
- // return false
- //}
- //for _, authPath := range m.AuthPaths {
- // if strings.HasSuffix(authPath, "/*") {
- // s.BindMiddleware(authPath, m.AuthMiddleware)
- // } else {
- // s.BindMiddleware(authPath+"/*", m.AuthMiddleware)
- // }
- //}
- // 登录
- //if m.LoginPath == "" || m.LoginBeforeFunc == nil {
- // glog.Error("[GToken]LoginPath or LoginBeforeFunc not set")
- // return false
- //}
- //s.BindHandler(m.LoginPath, m.Login)
- // 登出
- //if m.LogoutPath == "" {
- // glog.Error("[GToken]LogoutPath or LogoutFunc not set")
- // return false
- //}
- //s.BindHandler(m.LogoutPath, m.Logout)
- return true
- }
- // Start 结束
- func (m *GfToken) Stop() bool {
- glog.Info("[GToken]stop. ")
- return true
- }
- // GetTokenData 通过token获取对象
- func (m *GfToken) GetTokenData(r *ghttp.Request) Resp {
- respData := m.getRequestToken(r)
- if respData.Success() {
- // 验证token
- respData = m.validToken(respData.DataString())
- }
- return respData
- }
- // Login 登录
- func (m *GfToken) Login(r *ghttp.Request) {
- userKey, data := m.LoginBeforeFunc(r)
- if userKey == "" {
- glog.Error("[GToken]Login userKey is empty")
- return
- }
- if m.MultiLogin {
- // 支持多端重复登录,返回相同token
- userCacheResp := m.getToken(userKey, "")
- if userCacheResp.Success() {
- respToken := m.EncryptToken(userKey, "", userCacheResp.GetString("uuid"))
- m.LoginAfterFunc(r, respToken)
- return
- }
- }
- // 生成token
- respToken := m.genToken(userKey, "", "", data)
- m.LoginAfterFunc(r, respToken)
- }
- // Logout 登出
- func (m *GfToken) Logout(r *ghttp.Request) {
- if m.LogoutBeforeFunc(r) {
- // 获取请求token
- respData := m.getRequestToken(r)
- if respData.Success() {
- // 删除token
- m.removeToken(respData.DataString())
- }
- m.LogoutAfterFunc(r, respData)
- }
- }
- // AuthMiddleware 认证拦截
- func (m *GfToken) AuthMiddleware(r *ghttp.Request) {
- // 不需要认证,直接下一步
- if !m.AuthBeforeFunc(r) {
- r.Middleware.Next()
- return
- }
- // 获取请求token
- tokenResp := m.getRequestToken(r)
- if tokenResp.Success() {
- // 验证token
- tokenResp = m.validToken(tokenResp.DataString())
- }
- m.AuthAfterFunc(r, tokenResp)
- }
- // getRequestToken 返回请求Token
- func (m *GfToken) getRequestToken(r *ghttp.Request) Resp {
- authHeader := r.Header.Get("Authorization")
- if authHeader != "" {
- parts := strings.SplitN(authHeader, " ", 2)
- if !(len(parts) == 2 && parts[0] == "Bearer") {
- glog.Warning("[GToken]authHeader:" + authHeader + " get token key fail")
- return Unauthorized("get token key fail", "")
- } else if parts[1] == "" {
- glog.Warning("[GToken]authHeader:" + authHeader + " get token fail")
- return Unauthorized("get token fail", "")
- }
- return Succ(parts[1])
- }
- authHeader = r.GetString("token")
- if authHeader == "" {
- return Unauthorized("query token fail", "")
- }
- return Succ(authHeader)
- }
- // genToken 生成Token
- func (m *GfToken) genToken(tenant, userKey, uuid string, data interface{}) Resp {
- token := m.EncryptToken(tenant, userKey, uuid)
- if !token.Success() {
- return token
- }
- cacheKey := m.CacheKey + tenant + userKey
- userCache := g.Map{
- "tenant": tenant,
- "userKey": userKey,
- "uuid": token.GetString("uuid"),
- "data": data,
- "createTime": gtime.Now().Millisecond(),
- "refreshTime": gtime.Now().Millisecond() + m.MaxRefresh,
- }
- cacheResp := m.setCache(cacheKey, userCache)
- if !cacheResp.Success() {
- return cacheResp
- }
- return token
- }
- // validToken 验证Token
- func (m *GfToken) validToken(token string) Resp {
- if token == "" {
- return Unauthorized("valid token empty", "")
- }
- decryptToken := m.DecryptToken(token)
- if !decryptToken.Success() {
- return decryptToken
- }
- userKey := decryptToken.GetString("userKey")
- uuid := decryptToken.GetString("uuid")
- userCacheResp := m.getToken(userKey, "")
- if !userCacheResp.Success() {
- return userCacheResp
- }
- if uuid != userCacheResp.GetString("uuid") {
- glog.Error("[GToken]user auth error, decryptToken:" + decryptToken.Json() + " cacheValue:" + gconv.String(userCacheResp.Data))
- return Unauthorized("user auth error", "")
- }
- return userCacheResp
- }
- // getToken 通过userKey获取Token
- func (m *GfToken) getToken(tenant, userKey string) Resp {
- cacheKey := m.CacheKey + tenant + userKey
- userCacheResp := m.getCache(cacheKey)
- if !userCacheResp.Success() {
- return userCacheResp
- }
- userCache := gconv.Map(userCacheResp.Data)
- nowTime := gtime.Now().Millisecond()
- refreshTime := userCache["refreshTime"]
- // 需要进行缓存超时时间刷新
- if gconv.Int64(refreshTime) == 0 || nowTime > gconv.Int(refreshTime) {
- userCache["createTime"] = gtime.Now().Millisecond()
- userCache["refreshTime"] = gtime.Now().Millisecond() + m.MaxRefresh
- glog.Debug("[GToken]refreshToken:" + gconv.String(userCache))
- return m.setCache(cacheKey, userCache)
- }
- return Succ(userCache)
- }
- // removeToken 删除Token
- func (m *GfToken) removeToken(token string) Resp {
- decryptToken := m.DecryptToken(token)
- if !decryptToken.Success() {
- return decryptToken
- }
- cacheKey := m.CacheKey + decryptToken.GetString("userKey")
- return m.removeCache(cacheKey)
- }
- // EncryptToken token加密方法
- func (m *GfToken) EncryptToken(tenant, userKey string, uuid string) Resp {
- if userKey == "" {
- return Fail("encrypt userKey empty")
- }
- if tenant == "" {
- return Fail("encrypt tenant empty")
- }
- if uuid == "" {
- // 重新生成uuid
- newUuid, err := gmd5.Encrypt(grand.Str(utils.LetterDigits, 10))
- if err != nil {
- glog.Error("[GToken]uuid error", err)
- return Error("uuid error")
- }
- uuid = newUuid
- }
- tokenStr := tenant + m.TokenDelimiter + userKey + m.TokenDelimiter + uuid
- token, err := gaes.Encrypt([]byte(tokenStr), m.EncryptKey)
- if err != nil {
- glog.Error("[GToken]encrypt error", err)
- return Error("encrypt error")
- }
- return Succ(g.Map{
- "userKey": userKey,
- "tenant": tenant,
- "uuid": uuid,
- "token": string(gbase64.Encode(token)),
- })
- }
- // DecryptToken token解密方法
- func (m *GfToken) DecryptToken(token string) Resp {
- if token == "" {
- return Fail("decrypt token empty")
- }
- token64, err := gbase64.Decode([]byte(token))
- if err != nil {
- glog.Error("[GToken]decode error", err)
- return Error("decode error")
- }
- decryptToken, err2 := gaes.Decrypt([]byte(token64), m.EncryptKey)
- if err2 != nil {
- glog.Error("[GToken]decrypt error", err2)
- return Error("decrypt error")
- }
- tokenArray := gstr.Split(string(decryptToken), m.TokenDelimiter)
- if len(tokenArray) < 2 {
- glog.Error("[GToken]token len error")
- return Error("token len error")
- }
- return Succ(g.Map{
- "tenant": tokenArray[0],
- "userKey": tokenArray[1],
- "uuid": tokenArray[2],
- })
- }
- // String token解密方法
- func (m *GfToken) String() string {
- return gconv.String(g.Map{
- // 缓存模式 1 gcache 2 gredis 默认1
- "CacheMode": m.CacheMode,
- "CacheKey": m.CacheKey,
- "Timeout": m.Timeout,
- "TokenDelimiter": m.TokenDelimiter,
- "EncryptKey": string(m.EncryptKey),
- "LoginPath": m.LoginPath,
- "LogoutPath": m.LogoutPath,
- "AuthPaths": gconv.String(m.AuthPaths),
- })
- }
- // 微服务改造新增函数
- // 登录验证后获取或生成Token
- func (m *GfToken) GetOrGenToken(tenant, userKey, uuid string, data interface{}) Resp {
- if m.MultiLogin {
- // 支持多端重复登录,返回相同token
- userCacheResp := m.getToken(tenant, userKey)
- if userCacheResp.Success() {
- respToken := m.EncryptToken(tenant, userKey, userCacheResp.GetString("uuid"))
- return respToken
- }
- }
- // 生成token
- respToken := m.genToken(tenant, userKey, uuid, data)
- return respToken
- }
- // removeToken 删除Token
- func (m *GfToken) RemoveToken(token string) Resp {
- decryptToken := m.DecryptToken(token)
- if !decryptToken.Success() {
- return decryptToken
- }
- cacheKey := m.CacheKey + decryptToken.GetString("tenant") + decryptToken.GetString("userKey")
- return m.removeCache(cacheKey)
- }
- // validToken 验证Token
- func (m *GfToken) ValidToken(token string) Resp {
- if token == "" {
- return Unauthorized("valid token empty", "")
- }
- decryptToken := m.DecryptToken(token)
- if !decryptToken.Success() {
- return decryptToken
- }
- userKey := decryptToken.GetString("userKey")
- uuid := decryptToken.GetString("uuid")
- tenant := decryptToken.GetString("tenant")
- userCacheResp := m.getToken(tenant, userKey)
- if !userCacheResp.Success() {
- return userCacheResp
- }
- if uuid != userCacheResp.GetString("uuid") {
- glog.Error("[GToken]user auth error, decryptToken:" + decryptToken.Json() + " cacheValue:" + gconv.String(userCacheResp.Data))
- return Unauthorized("user auth error", "")
- }
- return userCacheResp
- }
|