gtoken.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. package gtoken
  2. import (
  3. "strings"
  4. "dashoo.cn/micro_libary/utils"
  5. "github.com/gogf/gf/crypto/gaes"
  6. "github.com/gogf/gf/crypto/gmd5"
  7. "github.com/gogf/gf/encoding/gbase64"
  8. "github.com/gogf/gf/frame/g"
  9. "github.com/gogf/gf/net/ghttp"
  10. "github.com/gogf/gf/os/glog"
  11. "github.com/gogf/gf/os/gtime"
  12. "github.com/gogf/gf/text/gstr"
  13. "github.com/gogf/gf/util/gconv"
  14. "github.com/gogf/gf/util/grand"
  15. )
  16. const (
  17. CacheModeCache = 1
  18. CacheModeRedis = 2
  19. )
  20. // GfToken gtoken结构体
  21. type GfToken struct {
  22. // 缓存模式 1 gcache 2 gredis 默认1
  23. CacheMode int8
  24. // 缓存key
  25. CacheKey string
  26. // 超时时间 默认10天
  27. Timeout int
  28. // 缓存刷新时间 默认为超时时间的一半
  29. MaxRefresh int
  30. // Token分隔符
  31. TokenDelimiter string
  32. // Token加密key
  33. EncryptKey []byte
  34. // 认证失败中文提示
  35. AuthFailMsg string
  36. // 是否支持多端登录,默认false
  37. MultiLogin bool
  38. // 登录路径
  39. LoginPath string
  40. // 登录验证方法 return userKey 用户标识 如果userKey为空,结束执行
  41. LoginBeforeFunc func(r *ghttp.Request) (string, interface{})
  42. // 登录返回方法
  43. LoginAfterFunc func(r *ghttp.Request, respData Resp)
  44. // 登出地址
  45. LogoutPath string
  46. // 登出验证方法 return true 继续执行,否则结束执行
  47. LogoutBeforeFunc func(r *ghttp.Request) bool
  48. // 登出返回方法
  49. LogoutAfterFunc func(r *ghttp.Request, respData Resp)
  50. // 拦截地址
  51. AuthPaths g.SliceStr
  52. // 认证验证方法 return true 继续执行,否则结束执行
  53. AuthBeforeFunc func(r *ghttp.Request) bool
  54. // 认证返回方法
  55. AuthAfterFunc func(r *ghttp.Request, respData Resp)
  56. }
  57. // Init 初始化
  58. func (m *GfToken) Init() bool {
  59. if m.CacheMode == 0 {
  60. m.CacheMode = CacheModeCache
  61. }
  62. if m.CacheKey == "" {
  63. m.CacheKey = "GToken:"
  64. }
  65. if m.Timeout == 0 {
  66. m.Timeout = 10 * 24 * 60 * 60 * 1000
  67. }
  68. if m.MaxRefresh == 0 {
  69. m.MaxRefresh = m.Timeout / 2
  70. }
  71. if m.TokenDelimiter == "" {
  72. m.TokenDelimiter = "_"
  73. }
  74. if len(m.EncryptKey) == 0 {
  75. m.EncryptKey = []byte("12345678912345678912345678912345")
  76. }
  77. if m.AuthFailMsg == "" {
  78. m.AuthFailMsg = "请求错误或登录超时"
  79. }
  80. //if m.LoginAfterFunc == nil {
  81. // m.LoginAfterFunc = func(r *ghttp.Request, respData Resp) {
  82. // if !respData.Success() {
  83. // r.Response.WriteJson(respData)
  84. // } else {
  85. // r.Response.WriteJson(Succ(g.Map{
  86. // "token": respData.GetString("token"),
  87. // }))
  88. // }
  89. // }
  90. //}
  91. //
  92. //if m.LogoutBeforeFunc == nil {
  93. // m.LogoutBeforeFunc = func(r *ghttp.Request) bool {
  94. // return true
  95. // }
  96. //}
  97. //
  98. //if m.LogoutAfterFunc == nil {
  99. // m.LogoutAfterFunc = func(r *ghttp.Request, respData Resp) {
  100. // if respData.Success() {
  101. // r.Response.WriteJson(Succ("Logout success"))
  102. // } else {
  103. // r.Response.WriteJson(respData)
  104. // }
  105. // }
  106. //}
  107. //
  108. //if m.AuthBeforeFunc == nil {
  109. // m.AuthBeforeFunc = func(r *ghttp.Request) bool {
  110. // // 静态页面不拦截
  111. // if r.IsFileRequest() {
  112. // return false
  113. // }
  114. //
  115. // return true
  116. // }
  117. //}
  118. //if m.AuthAfterFunc == nil {
  119. // m.AuthAfterFunc = func(r *ghttp.Request, respData Resp) {
  120. // if respData.Success() {
  121. // r.Middleware.Next()
  122. // } else {
  123. // var params map[string]interface{}
  124. // if r.Method == "GET" {
  125. // params = r.GetMap()
  126. // } else if r.Method == "POST" {
  127. // params = r.GetMap()
  128. // } else {
  129. // r.Response.Writeln("Request Method is ERROR! ")
  130. // return
  131. // }
  132. //
  133. // no := gconv.String(gtime.TimestampMilli())
  134. //
  135. // glog.Info(fmt.Sprintf("[AUTH_%s][url:%s][params:%s][data:%s]",
  136. // no, r.URL.Path, params, respData.Json()))
  137. // respData.Msg = m.AuthFailMsg
  138. // r.Response.WriteJson(respData)
  139. // r.ExitAll()
  140. // }
  141. // }
  142. //}
  143. return true
  144. }
  145. // Start 启动
  146. func (m *GfToken) Start() bool {
  147. if !m.Init() {
  148. return false
  149. }
  150. glog.Info("[GToken][params:" + m.String() + "]start... ")
  151. //s := g.Server()
  152. // 缓存模式
  153. if m.CacheMode > CacheModeRedis {
  154. glog.Error("[GToken]CacheMode set error")
  155. return false
  156. }
  157. // 认证拦截器
  158. //if m.AuthPaths == nil {
  159. // glog.Error("[GToken]HookPathList not set")
  160. // return false
  161. //}
  162. //for _, authPath := range m.AuthPaths {
  163. // if strings.HasSuffix(authPath, "/*") {
  164. // s.BindMiddleware(authPath, m.AuthMiddleware)
  165. // } else {
  166. // s.BindMiddleware(authPath+"/*", m.AuthMiddleware)
  167. // }
  168. //}
  169. // 登录
  170. //if m.LoginPath == "" || m.LoginBeforeFunc == nil {
  171. // glog.Error("[GToken]LoginPath or LoginBeforeFunc not set")
  172. // return false
  173. //}
  174. //s.BindHandler(m.LoginPath, m.Login)
  175. // 登出
  176. //if m.LogoutPath == "" {
  177. // glog.Error("[GToken]LogoutPath or LogoutFunc not set")
  178. // return false
  179. //}
  180. //s.BindHandler(m.LogoutPath, m.Logout)
  181. return true
  182. }
  183. // Start 结束
  184. func (m *GfToken) Stop() bool {
  185. glog.Info("[GToken]stop. ")
  186. return true
  187. }
  188. // GetTokenData 通过token获取对象
  189. func (m *GfToken) GetTokenData(r *ghttp.Request) Resp {
  190. respData := m.getRequestToken(r)
  191. if respData.Success() {
  192. // 验证token
  193. respData = m.validToken(respData.DataString())
  194. }
  195. return respData
  196. }
  197. // Login 登录
  198. func (m *GfToken) Login(r *ghttp.Request) {
  199. userKey, data := m.LoginBeforeFunc(r)
  200. if userKey == "" {
  201. glog.Error("[GToken]Login userKey is empty")
  202. return
  203. }
  204. if m.MultiLogin {
  205. // 支持多端重复登录,返回相同token
  206. userCacheResp := m.getToken(userKey, "")
  207. if userCacheResp.Success() {
  208. respToken := m.EncryptToken(userKey, "", userCacheResp.GetString("uuid"))
  209. m.LoginAfterFunc(r, respToken)
  210. return
  211. }
  212. }
  213. // 生成token
  214. respToken := m.genToken(userKey, "", "", data)
  215. m.LoginAfterFunc(r, respToken)
  216. }
  217. // Logout 登出
  218. func (m *GfToken) Logout(r *ghttp.Request) {
  219. if m.LogoutBeforeFunc(r) {
  220. // 获取请求token
  221. respData := m.getRequestToken(r)
  222. if respData.Success() {
  223. // 删除token
  224. m.removeToken(respData.DataString())
  225. }
  226. m.LogoutAfterFunc(r, respData)
  227. }
  228. }
  229. // AuthMiddleware 认证拦截
  230. func (m *GfToken) AuthMiddleware(r *ghttp.Request) {
  231. // 不需要认证,直接下一步
  232. if !m.AuthBeforeFunc(r) {
  233. r.Middleware.Next()
  234. return
  235. }
  236. // 获取请求token
  237. tokenResp := m.getRequestToken(r)
  238. if tokenResp.Success() {
  239. // 验证token
  240. tokenResp = m.validToken(tokenResp.DataString())
  241. }
  242. m.AuthAfterFunc(r, tokenResp)
  243. }
  244. // getRequestToken 返回请求Token
  245. func (m *GfToken) getRequestToken(r *ghttp.Request) Resp {
  246. authHeader := r.Header.Get("Authorization")
  247. if authHeader != "" {
  248. parts := strings.SplitN(authHeader, " ", 2)
  249. if !(len(parts) == 2 && parts[0] == "Bearer") {
  250. glog.Warning("[GToken]authHeader:" + authHeader + " get token key fail")
  251. return Unauthorized("get token key fail", "")
  252. } else if parts[1] == "" {
  253. glog.Warning("[GToken]authHeader:" + authHeader + " get token fail")
  254. return Unauthorized("get token fail", "")
  255. }
  256. return Succ(parts[1])
  257. }
  258. authHeader = r.GetString("token")
  259. if authHeader == "" {
  260. return Unauthorized("query token fail", "")
  261. }
  262. return Succ(authHeader)
  263. }
  264. // genToken 生成Token
  265. func (m *GfToken) genToken(tenant, userKey, uuid string, data interface{}) Resp {
  266. token := m.EncryptToken(tenant, userKey, uuid)
  267. if !token.Success() {
  268. return token
  269. }
  270. cacheKey := m.CacheKey + tenant + userKey
  271. userCache := g.Map{
  272. "tenant": tenant,
  273. "userKey": userKey,
  274. "uuid": token.GetString("uuid"),
  275. "data": data,
  276. "createTime": gtime.Now().Millisecond(),
  277. "refreshTime": gtime.Now().Millisecond() + m.MaxRefresh,
  278. }
  279. cacheResp := m.setCache(cacheKey, userCache)
  280. if !cacheResp.Success() {
  281. return cacheResp
  282. }
  283. return token
  284. }
  285. // validToken 验证Token
  286. func (m *GfToken) validToken(token string) Resp {
  287. if token == "" {
  288. return Unauthorized("valid token empty", "")
  289. }
  290. decryptToken := m.DecryptToken(token)
  291. if !decryptToken.Success() {
  292. return decryptToken
  293. }
  294. userKey := decryptToken.GetString("userKey")
  295. uuid := decryptToken.GetString("uuid")
  296. userCacheResp := m.getToken(userKey, "")
  297. if !userCacheResp.Success() {
  298. return userCacheResp
  299. }
  300. if uuid != userCacheResp.GetString("uuid") {
  301. glog.Error("[GToken]user auth error, decryptToken:" + decryptToken.Json() + " cacheValue:" + gconv.String(userCacheResp.Data))
  302. return Unauthorized("user auth error", "")
  303. }
  304. return userCacheResp
  305. }
  306. // getToken 通过userKey获取Token
  307. func (m *GfToken) getToken(tenant, userKey string) Resp {
  308. cacheKey := m.CacheKey + tenant + userKey
  309. userCacheResp := m.getCache(cacheKey)
  310. if !userCacheResp.Success() {
  311. return userCacheResp
  312. }
  313. userCache := gconv.Map(userCacheResp.Data)
  314. nowTime := gtime.Now().Millisecond()
  315. refreshTime := userCache["refreshTime"]
  316. // 需要进行缓存超时时间刷新
  317. if gconv.Int64(refreshTime) == 0 || nowTime > gconv.Int(refreshTime) {
  318. userCache["createTime"] = gtime.Now().Millisecond()
  319. userCache["refreshTime"] = gtime.Now().Millisecond() + m.MaxRefresh
  320. glog.Debug("[GToken]refreshToken:" + gconv.String(userCache))
  321. return m.setCache(cacheKey, userCache)
  322. }
  323. return Succ(userCache)
  324. }
  325. // removeToken 删除Token
  326. func (m *GfToken) removeToken(token string) Resp {
  327. decryptToken := m.DecryptToken(token)
  328. if !decryptToken.Success() {
  329. return decryptToken
  330. }
  331. cacheKey := m.CacheKey + decryptToken.GetString("userKey")
  332. return m.removeCache(cacheKey)
  333. }
  334. // EncryptToken token加密方法
  335. func (m *GfToken) EncryptToken(tenant, userKey string, uuid string) Resp {
  336. if userKey == "" {
  337. return Fail("encrypt userKey empty")
  338. }
  339. if tenant == "" {
  340. return Fail("encrypt tenant empty")
  341. }
  342. if uuid == "" {
  343. // 重新生成uuid
  344. newUuid, err := gmd5.Encrypt(grand.Str(utils.LetterDigits, 10))
  345. if err != nil {
  346. glog.Error("[GToken]uuid error", err)
  347. return Error("uuid error")
  348. }
  349. uuid = newUuid
  350. }
  351. tokenStr := tenant + m.TokenDelimiter + userKey + m.TokenDelimiter + uuid
  352. token, err := gaes.Encrypt([]byte(tokenStr), m.EncryptKey)
  353. if err != nil {
  354. glog.Error("[GToken]encrypt error", err)
  355. return Error("encrypt error")
  356. }
  357. return Succ(g.Map{
  358. "userKey": userKey,
  359. "tenant": tenant,
  360. "uuid": uuid,
  361. "token": string(gbase64.Encode(token)),
  362. })
  363. }
  364. // DecryptToken token解密方法
  365. func (m *GfToken) DecryptToken(token string) Resp {
  366. if token == "" {
  367. return Fail("decrypt token empty")
  368. }
  369. token64, err := gbase64.Decode([]byte(token))
  370. if err != nil {
  371. glog.Error("[GToken]decode error", err)
  372. return Error("decode error")
  373. }
  374. decryptToken, err2 := gaes.Decrypt([]byte(token64), m.EncryptKey)
  375. if err2 != nil {
  376. glog.Error("[GToken]decrypt error", err2)
  377. return Error("decrypt error")
  378. }
  379. tokenArray := gstr.Split(string(decryptToken), m.TokenDelimiter)
  380. if len(tokenArray) < 2 {
  381. glog.Error("[GToken]token len error")
  382. return Error("token len error")
  383. }
  384. return Succ(g.Map{
  385. "tenant": tokenArray[0],
  386. "userKey": tokenArray[1],
  387. "uuid": tokenArray[2],
  388. })
  389. }
  390. // String token解密方法
  391. func (m *GfToken) String() string {
  392. return gconv.String(g.Map{
  393. // 缓存模式 1 gcache 2 gredis 默认1
  394. "CacheMode": m.CacheMode,
  395. "CacheKey": m.CacheKey,
  396. "Timeout": m.Timeout,
  397. "TokenDelimiter": m.TokenDelimiter,
  398. "EncryptKey": string(m.EncryptKey),
  399. "LoginPath": m.LoginPath,
  400. "LogoutPath": m.LogoutPath,
  401. "AuthPaths": gconv.String(m.AuthPaths),
  402. })
  403. }
  404. // 微服务改造新增函数
  405. // 登录验证后获取或生成Token
  406. func (m *GfToken) GetOrGenToken(tenant, userKey, uuid string, data interface{}) Resp {
  407. if m.MultiLogin {
  408. // 支持多端重复登录,返回相同token
  409. userCacheResp := m.getToken(tenant, userKey)
  410. if userCacheResp.Success() {
  411. respToken := m.EncryptToken(tenant, userKey, userCacheResp.GetString("uuid"))
  412. return respToken
  413. }
  414. }
  415. // 生成token
  416. respToken := m.genToken(tenant, userKey, uuid, data)
  417. return respToken
  418. }
  419. // removeToken 删除Token
  420. func (m *GfToken) RemoveToken(token string) Resp {
  421. decryptToken := m.DecryptToken(token)
  422. if !decryptToken.Success() {
  423. return decryptToken
  424. }
  425. cacheKey := m.CacheKey + decryptToken.GetString("tenant") + decryptToken.GetString("userKey")
  426. return m.removeCache(cacheKey)
  427. }
  428. // validToken 验证Token
  429. func (m *GfToken) ValidToken(token string) Resp {
  430. if token == "" {
  431. return Unauthorized("valid token empty", "")
  432. }
  433. decryptToken := m.DecryptToken(token)
  434. if !decryptToken.Success() {
  435. return decryptToken
  436. }
  437. userKey := decryptToken.GetString("userKey")
  438. uuid := decryptToken.GetString("uuid")
  439. tenant := decryptToken.GetString("tenant")
  440. userCacheResp := m.getToken(tenant, userKey)
  441. if !userCacheResp.Success() {
  442. return userCacheResp
  443. }
  444. if uuid != userCacheResp.GetString("uuid") {
  445. glog.Error("[GToken]user auth error, decryptToken:" + decryptToken.Json() + " cacheValue:" + gconv.String(userCacheResp.Data))
  446. return Unauthorized("user auth error", "")
  447. }
  448. return userCacheResp
  449. }