gtoken.go 12 KB

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