1
0

token.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. package token
  2. import (
  3. "context"
  4. "dashoo.cn/micro_libary/micro"
  5. "fmt"
  6. "github.com/gogf/gf/v2/crypto/gaes"
  7. "github.com/gogf/gf/v2/crypto/gmd5"
  8. "github.com/gogf/gf/v2/encoding/gbase64"
  9. "github.com/gogf/gf/v2/frame/g"
  10. "github.com/gogf/gf/v2/os/gctx"
  11. "github.com/gogf/gf/v2/os/gtime"
  12. "github.com/gogf/gf/v2/text/gstr"
  13. "github.com/gogf/gf/v2/util/gconv"
  14. "github.com/gogf/gf/v2/util/grand"
  15. "github.com/smallnest/rpcx/protocol"
  16. "strings"
  17. )
  18. // RpcxToken 结构体
  19. type RpcxToken struct {
  20. // 缓存模式 1 gcache 2 gredis 默认1
  21. CacheMode int64
  22. // 缓存key
  23. CacheKey string
  24. // 超时时间 默认10天(毫秒)
  25. Timeout int64
  26. // 缓存刷新时间 默认为超时时间的一半(毫秒)
  27. MaxRefresh int64
  28. // Token分隔符
  29. TokenDelimiter string
  30. // Token加密key
  31. EncryptKey []byte
  32. // 认证失败中文提示
  33. AuthFailMsg string
  34. // 是否支持多端登录,默认false
  35. MultiLogin bool
  36. // 中间件类型 1 GroupMiddleware 2 BindMiddleware 3 GlobalMiddleware
  37. MiddlewareType int64
  38. // 拦截地址
  39. AuthPaths []string
  40. // 拦截排除地址
  41. AuthExcludePaths []string
  42. // 认证验证方法 return true 继续执行,否则结束执行
  43. AuthBeforeFunc func(req *protocol.Message) bool
  44. // 认证返回方法
  45. AuthAfterFunc func(req *protocol.Message, resp micro.Response)
  46. }
  47. func NewRpcxToken() *RpcxToken {
  48. m := new(RpcxToken)
  49. ctx := gctx.New()
  50. cacheMode, err := g.Config().Get(ctx, "token.cache-mode")
  51. if err != nil || cacheMode.Int64() == 0 {
  52. m.CacheMode = CacheModeCache
  53. } else {
  54. m.CacheMode = cacheMode.Int64()
  55. }
  56. cacheKey, err := g.Config().Get(ctx, "token.cache-key")
  57. if err != nil || cacheKey.String() == "" {
  58. m.CacheKey = DefaultCacheKey
  59. } else {
  60. m.CacheKey = cacheKey.String()
  61. }
  62. timeout, err := g.Config().Get(ctx, "token.timeout")
  63. if err != nil || timeout.Int64() == 0 {
  64. m.Timeout = DefaultTimeout
  65. } else {
  66. m.Timeout = timeout.Int64()
  67. }
  68. maxRefresh, err := g.Config().Get(ctx, "token.max-refresh")
  69. if err != nil || maxRefresh.Int64() == 0 {
  70. m.MaxRefresh = m.Timeout / 2
  71. } else {
  72. m.MaxRefresh = maxRefresh.Int64()
  73. }
  74. tokenDelimiter, err := g.Config().Get(ctx, "token.token-delimiter")
  75. if err != nil || tokenDelimiter.String() == "" {
  76. m.TokenDelimiter = DefaultTokenDelimiter
  77. } else {
  78. m.TokenDelimiter = tokenDelimiter.String()
  79. }
  80. encryptKey, err := g.Config().Get(ctx, "token.encrypt-key")
  81. if err != nil || len(encryptKey.String()) == 0 {
  82. m.EncryptKey = []byte(DefaultEncryptKey)
  83. } else {
  84. m.EncryptKey = []byte(encryptKey.String())
  85. }
  86. authFailMsg, err := g.Config().Get(ctx, "token.auth-fail-msg")
  87. if err != nil || authFailMsg.String() == "" {
  88. m.AuthFailMsg = DefaultAuthFailMsg
  89. } else {
  90. m.AuthFailMsg = authFailMsg.String()
  91. }
  92. multiLogin, err := g.Config().Get(ctx, "token.multi-login")
  93. if err != nil || multiLogin.String() == "" {
  94. m.MultiLogin = false
  95. } else {
  96. m.MultiLogin = authFailMsg.Bool()
  97. }
  98. return m
  99. }
  100. // GenToken 生成Token
  101. func (m *RpcxToken) GenToken(ctx context.Context, userKey string, data interface{}) *micro.Response {
  102. token := m.EncryptToken(ctx, userKey, "")
  103. if !token.IsSuccess() {
  104. return token
  105. }
  106. cacheKey := m.CacheKey + userKey
  107. userCache := g.Map{
  108. KeyUserKey: userKey,
  109. KeyUuid: token.Get(KeyUuid).String(),
  110. KeyData: data,
  111. KeyCreateTime: gtime.Now().TimestampMilli(),
  112. KeyRefreshTime: gtime.Now().TimestampMilli() + gconv.Int64(m.MaxRefresh),
  113. }
  114. cacheResp := m.setCache(ctx, cacheKey, userCache)
  115. if !cacheResp.IsSuccess() {
  116. return cacheResp
  117. }
  118. return token
  119. }
  120. // GetTokenData 通过token获取对象
  121. func (m *RpcxToken) GetTokenData(ctx context.Context, req *protocol.Message) *micro.Response {
  122. respData := m.GetRequestToken(ctx, req)
  123. if respData.IsSuccess() {
  124. // 验证token
  125. respData = m.validToken(ctx, respData.String())
  126. }
  127. return respData
  128. }
  129. // getRequestToken 返回请求Token
  130. func (m *RpcxToken) GetRequestToken(ctx context.Context, req *protocol.Message) *micro.Response {
  131. authHeader := req.Metadata["Authorization"]
  132. if authHeader != "" {
  133. parts := strings.SplitN(authHeader, " ", 2)
  134. if !(len(parts) == 2 && parts[0] == "Bearer") {
  135. g.Log().Warning(ctx, msgLog(MsgErrAuthHeader, authHeader))
  136. return micro.Unauthorized(fmt.Sprintf(MsgErrAuthHeader, authHeader), "")
  137. } else if parts[1] == "" {
  138. g.Log().Warning(ctx, msgLog(MsgErrAuthHeader, authHeader))
  139. return micro.Unauthorized(fmt.Sprintf(MsgErrAuthHeader, authHeader), "")
  140. }
  141. return micro.Success(parts[1])
  142. }
  143. authHeader = req.Metadata[KeyToken]
  144. if authHeader == "" {
  145. return micro.Unauthorized(MsgErrTokenEmpty, "")
  146. }
  147. return micro.Success(authHeader)
  148. }
  149. // validToken 验证Token
  150. func (m *RpcxToken) validToken(ctx context.Context, token string) *micro.Response {
  151. if token == "" {
  152. return micro.Unauthorized(MsgErrTokenEmpty, "")
  153. }
  154. decryptToken := m.DecryptToken(ctx, token)
  155. if !decryptToken.IsSuccess() {
  156. return decryptToken
  157. }
  158. userKey := decryptToken.Get(KeyUserKey)
  159. uuid := decryptToken.Get(KeyUuid)
  160. userCacheResp := m.GetToken(ctx, userKey.String())
  161. if !userCacheResp.IsSuccess() {
  162. return userCacheResp
  163. }
  164. if uuid.String() != userCacheResp.Get(KeyUuid).String() {
  165. g.Log().Debug(ctx, msgLog(MsgErrAuthUuid)+", decryptToken:"+decryptToken.Json()+" cacheValue:"+gconv.String(userCacheResp.Data))
  166. return micro.Unauthorized(MsgErrAuthUuid, "")
  167. }
  168. return userCacheResp
  169. }
  170. // GetToken 通过userKey获取Token
  171. func (m *RpcxToken) GetToken(ctx context.Context, userKey string) *micro.Response {
  172. cacheKey := m.CacheKey + userKey
  173. userCacheResp := m.getCache(ctx, cacheKey)
  174. if !userCacheResp.IsSuccess() {
  175. return userCacheResp
  176. }
  177. userCache := gconv.Map(userCacheResp.Data)
  178. nowTime := gtime.Now().TimestampMilli()
  179. refreshTime := userCache[KeyRefreshTime]
  180. // 需要进行缓存超时时间刷新
  181. if gconv.Int64(refreshTime) == 0 || nowTime > gconv.Int64(refreshTime) {
  182. userCache[KeyCreateTime] = gtime.Now().TimestampMilli()
  183. userCache[KeyRefreshTime] = gtime.Now().TimestampMilli() + gconv.Int64(m.MaxRefresh)
  184. return m.setCache(ctx, cacheKey, userCache)
  185. }
  186. return micro.Success(userCache)
  187. }
  188. // RemoveToken 删除Token
  189. func (m *RpcxToken) RemoveToken(ctx context.Context, token string) *micro.Response {
  190. decryptToken := m.DecryptToken(ctx, token)
  191. if !decryptToken.IsSuccess() {
  192. return decryptToken
  193. }
  194. cacheKey := m.CacheKey + decryptToken.Get(KeyUserKey).String()
  195. return m.removeCache(ctx, cacheKey)
  196. }
  197. // EncryptToken token加密方法
  198. func (m *RpcxToken) EncryptToken(ctx context.Context, userKey string, uuid string) *micro.Response {
  199. if userKey == "" {
  200. return micro.Fail(MsgErrUserKeyEmpty)
  201. }
  202. if uuid == "" {
  203. // 重新生成uuid
  204. newUuid, err := gmd5.Encrypt(grand.Letters(10))
  205. if err != nil {
  206. g.Log().Error(ctx, msgLog(MsgErrAuthUuid), err)
  207. return micro.Error(MsgErrAuthUuid)
  208. }
  209. uuid = newUuid
  210. }
  211. tokenStr := userKey + m.TokenDelimiter + uuid
  212. token, err := gaes.Encrypt([]byte(tokenStr), m.EncryptKey)
  213. if err != nil {
  214. g.Log().Error(ctx, msgLog(MsgErrTokenEncrypt), tokenStr, err)
  215. return micro.Error(MsgErrTokenEncrypt)
  216. }
  217. return micro.Success(g.Map{
  218. //KeyUserKey: userKey,
  219. KeyUuid: uuid,
  220. KeyToken: gbase64.EncodeToString(token),
  221. })
  222. }
  223. // DecryptToken token解密方法
  224. func (m *RpcxToken) DecryptToken(ctx context.Context, token string) *micro.Response {
  225. if token == "" {
  226. return micro.Fail(MsgErrTokenEmpty)
  227. }
  228. token64, err := gbase64.Decode([]byte(token))
  229. if err != nil {
  230. g.Log().Error(ctx, msgLog(MsgErrTokenDecode), token, err)
  231. return micro.Error(MsgErrTokenDecode)
  232. }
  233. decryptToken, err2 := gaes.Decrypt(token64, m.EncryptKey)
  234. if err2 != nil {
  235. g.Log().Error(ctx, msgLog(MsgErrTokenEncrypt), token, err2)
  236. return micro.Error(MsgErrTokenEncrypt)
  237. }
  238. tokenArray := gstr.Split(string(decryptToken), m.TokenDelimiter)
  239. if len(tokenArray) < 2 {
  240. g.Log().Error(ctx, msgLog(MsgErrTokenLen), token)
  241. return micro.Error(MsgErrTokenLen)
  242. }
  243. return micro.Success(g.Map{
  244. KeyUserKey: tokenArray[0],
  245. KeyUuid: tokenArray[1],
  246. })
  247. }
  248. // String token解密方法
  249. func (m *RpcxToken) String() string {
  250. return gconv.String(g.Map{
  251. // 缓存模式 1 gcache 2 gredis 默认1
  252. "CacheMode": m.CacheMode,
  253. "CacheKey": m.CacheKey,
  254. "Timeout": m.Timeout,
  255. "TokenDelimiter": m.TokenDelimiter,
  256. "AuthFailMsg": m.AuthFailMsg,
  257. "MultiLogin": m.MultiLogin,
  258. "MiddlewareType": m.MiddlewareType,
  259. "AuthPaths": gconv.String(m.AuthPaths),
  260. "AuthExcludePaths": gconv.String(m.AuthExcludePaths),
  261. })
  262. }