| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- package token
- import (
- "context"
- "dashoo.cn/micro_libary/micro"
- "fmt"
- "github.com/gogf/gf/v2/crypto/gaes"
- "github.com/gogf/gf/v2/crypto/gmd5"
- "github.com/gogf/gf/v2/encoding/gbase64"
- "github.com/gogf/gf/v2/frame/g"
- "github.com/gogf/gf/v2/os/gctx"
- "github.com/gogf/gf/v2/os/gtime"
- "github.com/gogf/gf/v2/text/gstr"
- "github.com/gogf/gf/v2/util/gconv"
- "github.com/gogf/gf/v2/util/grand"
- "github.com/smallnest/rpcx/protocol"
- "strings"
- )
- // RpcxToken 结构体
- type RpcxToken struct {
- // 缓存模式 1 gcache 2 gredis 默认1
- CacheMode int64
- // 缓存key
- CacheKey string
- // 超时时间 默认10天(毫秒)
- Timeout int64
- // 缓存刷新时间 默认为超时时间的一半(毫秒)
- MaxRefresh int64
- // Token分隔符
- TokenDelimiter string
- // Token加密key
- EncryptKey []byte
- // 认证失败中文提示
- AuthFailMsg string
- // 是否支持多端登录,默认false
- MultiLogin bool
- // 中间件类型 1 GroupMiddleware 2 BindMiddleware 3 GlobalMiddleware
- MiddlewareType int64
- // 拦截地址
- AuthPaths []string
- // 拦截排除地址
- AuthExcludePaths []string
- // 认证验证方法 return true 继续执行,否则结束执行
- AuthBeforeFunc func(req *protocol.Message) bool
- // 认证返回方法
- AuthAfterFunc func(req *protocol.Message, resp micro.Response)
- }
- func NewRpcxToken() *RpcxToken {
- m := new(RpcxToken)
- ctx := gctx.New()
- cacheMode, err := g.Config().Get(ctx, "token.cache-mode")
- if err != nil || cacheMode.Int64() == 0 {
- m.CacheMode = CacheModeCache
- } else {
- m.CacheMode = cacheMode.Int64()
- }
- cacheKey, err := g.Config().Get(ctx, "token.cache-key")
- if err != nil || cacheKey.String() == "" {
- m.CacheKey = DefaultCacheKey
- } else {
- m.CacheKey = cacheKey.String()
- }
- timeout, err := g.Config().Get(ctx, "token.timeout")
- if err != nil || timeout.Int64() == 0 {
- m.Timeout = DefaultTimeout
- } else {
- m.Timeout = timeout.Int64()
- }
- maxRefresh, err := g.Config().Get(ctx, "token.max-refresh")
- if err != nil || maxRefresh.Int64() == 0 {
- m.MaxRefresh = m.Timeout / 2
- } else {
- m.MaxRefresh = maxRefresh.Int64()
- }
- tokenDelimiter, err := g.Config().Get(ctx, "token.token-delimiter")
- if err != nil || tokenDelimiter.String() == "" {
- m.TokenDelimiter = DefaultTokenDelimiter
- } else {
- m.TokenDelimiter = tokenDelimiter.String()
- }
- encryptKey, err := g.Config().Get(ctx, "token.encrypt-key")
- if err != nil || len(encryptKey.String()) == 0 {
- m.EncryptKey = []byte(DefaultEncryptKey)
- } else {
- m.EncryptKey = []byte(encryptKey.String())
- }
- authFailMsg, err := g.Config().Get(ctx, "token.auth-fail-msg")
- if err != nil || authFailMsg.String() == "" {
- m.AuthFailMsg = DefaultAuthFailMsg
- } else {
- m.AuthFailMsg = authFailMsg.String()
- }
- multiLogin, err := g.Config().Get(ctx, "token.multi-login")
- if err != nil || multiLogin.String() == "" {
- m.MultiLogin = false
- } else {
- m.MultiLogin = authFailMsg.Bool()
- }
- return m
- }
- // GenToken 生成Token
- func (m *RpcxToken) GenToken(ctx context.Context, userKey string, data interface{}) *micro.Response {
- token := m.EncryptToken(ctx, userKey, "")
- if !token.IsSuccess() {
- return token
- }
- cacheKey := m.CacheKey + userKey
- userCache := g.Map{
- KeyUserKey: userKey,
- KeyUuid: token.Get(KeyUuid).String(),
- KeyData: data,
- KeyCreateTime: gtime.Now().TimestampMilli(),
- KeyRefreshTime: gtime.Now().TimestampMilli() + gconv.Int64(m.MaxRefresh),
- }
- cacheResp := m.setCache(ctx, cacheKey, userCache)
- if !cacheResp.IsSuccess() {
- return cacheResp
- }
- return token
- }
- // GetTokenData 通过token获取对象
- func (m *RpcxToken) GetTokenData(ctx context.Context, req *protocol.Message) *micro.Response {
- respData := m.GetRequestToken(ctx, req)
- if respData.IsSuccess() {
- // 验证token
- respData = m.validToken(ctx, respData.String())
- }
- return respData
- }
- // getRequestToken 返回请求Token
- func (m *RpcxToken) GetRequestToken(ctx context.Context, req *protocol.Message) *micro.Response {
- authHeader := req.Metadata["Authorization"]
- if authHeader != "" {
- parts := strings.SplitN(authHeader, " ", 2)
- if !(len(parts) == 2 && parts[0] == "Bearer") {
- g.Log().Warning(ctx, msgLog(MsgErrAuthHeader, authHeader))
- return micro.Unauthorized(fmt.Sprintf(MsgErrAuthHeader, authHeader), "")
- } else if parts[1] == "" {
- g.Log().Warning(ctx, msgLog(MsgErrAuthHeader, authHeader))
- return micro.Unauthorized(fmt.Sprintf(MsgErrAuthHeader, authHeader), "")
- }
- return micro.Success(parts[1])
- }
- authHeader = req.Metadata[KeyToken]
- if authHeader == "" {
- return micro.Unauthorized(MsgErrTokenEmpty, "")
- }
- return micro.Success(authHeader)
- }
- // validToken 验证Token
- func (m *RpcxToken) validToken(ctx context.Context, token string) *micro.Response {
- if token == "" {
- return micro.Unauthorized(MsgErrTokenEmpty, "")
- }
- decryptToken := m.DecryptToken(ctx, token)
- if !decryptToken.IsSuccess() {
- return decryptToken
- }
- userKey := decryptToken.Get(KeyUserKey)
- uuid := decryptToken.Get(KeyUuid)
- userCacheResp := m.GetToken(ctx, userKey.String())
- if !userCacheResp.IsSuccess() {
- return userCacheResp
- }
- if uuid.String() != userCacheResp.Get(KeyUuid).String() {
- g.Log().Debug(ctx, msgLog(MsgErrAuthUuid)+", decryptToken:"+decryptToken.Json()+" cacheValue:"+gconv.String(userCacheResp.Data))
- return micro.Unauthorized(MsgErrAuthUuid, "")
- }
- return userCacheResp
- }
- // GetToken 通过userKey获取Token
- func (m *RpcxToken) GetToken(ctx context.Context, userKey string) *micro.Response {
- cacheKey := m.CacheKey + userKey
- userCacheResp := m.getCache(ctx, cacheKey)
- if !userCacheResp.IsSuccess() {
- return userCacheResp
- }
- userCache := gconv.Map(userCacheResp.Data)
- nowTime := gtime.Now().TimestampMilli()
- refreshTime := userCache[KeyRefreshTime]
- // 需要进行缓存超时时间刷新
- if gconv.Int64(refreshTime) == 0 || nowTime > gconv.Int64(refreshTime) {
- userCache[KeyCreateTime] = gtime.Now().TimestampMilli()
- userCache[KeyRefreshTime] = gtime.Now().TimestampMilli() + gconv.Int64(m.MaxRefresh)
- return m.setCache(ctx, cacheKey, userCache)
- }
- return micro.Success(userCache)
- }
- // RemoveToken 删除Token
- func (m *RpcxToken) RemoveToken(ctx context.Context, token string) *micro.Response {
- decryptToken := m.DecryptToken(ctx, token)
- if !decryptToken.IsSuccess() {
- return decryptToken
- }
- cacheKey := m.CacheKey + decryptToken.Get(KeyUserKey).String()
- return m.removeCache(ctx, cacheKey)
- }
- // EncryptToken token加密方法
- func (m *RpcxToken) EncryptToken(ctx context.Context, userKey string, uuid string) *micro.Response {
- if userKey == "" {
- return micro.Fail(MsgErrUserKeyEmpty)
- }
- if uuid == "" {
- // 重新生成uuid
- newUuid, err := gmd5.Encrypt(grand.Letters(10))
- if err != nil {
- g.Log().Error(ctx, msgLog(MsgErrAuthUuid), err)
- return micro.Error(MsgErrAuthUuid)
- }
- uuid = newUuid
- }
- tokenStr := userKey + m.TokenDelimiter + uuid
- token, err := gaes.Encrypt([]byte(tokenStr), m.EncryptKey)
- if err != nil {
- g.Log().Error(ctx, msgLog(MsgErrTokenEncrypt), tokenStr, err)
- return micro.Error(MsgErrTokenEncrypt)
- }
- return micro.Success(g.Map{
- //KeyUserKey: userKey,
- KeyUuid: uuid,
- KeyToken: gbase64.EncodeToString(token),
- })
- }
- // DecryptToken token解密方法
- func (m *RpcxToken) DecryptToken(ctx context.Context, token string) *micro.Response {
- if token == "" {
- return micro.Fail(MsgErrTokenEmpty)
- }
- token64, err := gbase64.Decode([]byte(token))
- if err != nil {
- g.Log().Error(ctx, msgLog(MsgErrTokenDecode), token, err)
- return micro.Error(MsgErrTokenDecode)
- }
- decryptToken, err2 := gaes.Decrypt(token64, m.EncryptKey)
- if err2 != nil {
- g.Log().Error(ctx, msgLog(MsgErrTokenEncrypt), token, err2)
- return micro.Error(MsgErrTokenEncrypt)
- }
- tokenArray := gstr.Split(string(decryptToken), m.TokenDelimiter)
- if len(tokenArray) < 2 {
- g.Log().Error(ctx, msgLog(MsgErrTokenLen), token)
- return micro.Error(MsgErrTokenLen)
- }
- return micro.Success(g.Map{
- KeyUserKey: tokenArray[0],
- KeyUuid: tokenArray[1],
- })
- }
- // String token解密方法
- func (m *RpcxToken) String() string {
- return gconv.String(g.Map{
- // 缓存模式 1 gcache 2 gredis 默认1
- "CacheMode": m.CacheMode,
- "CacheKey": m.CacheKey,
- "Timeout": m.Timeout,
- "TokenDelimiter": m.TokenDelimiter,
- "AuthFailMsg": m.AuthFailMsg,
- "MultiLogin": m.MultiLogin,
- "MiddlewareType": m.MiddlewareType,
- "AuthPaths": gconv.String(m.AuthPaths),
- "AuthExcludePaths": gconv.String(m.AuthExcludePaths),
- })
- }
|