Files
open-im-server/pkg/common/token_verify/jwt_token.go
T

232 lines
7.0 KiB
Go
Raw Normal View History

2021-11-25 14:12:52 +08:00
package token_verify
import (
"Open_IM/pkg/common/config"
"Open_IM/pkg/common/constant"
commonDB "Open_IM/pkg/common/db"
"Open_IM/pkg/common/log"
2021-12-23 17:22:49 +08:00
"Open_IM/pkg/utils"
2021-12-28 10:59:01 +08:00
"github.com/garyburd/redigo/redis"
2021-11-25 14:12:52 +08:00
"github.com/golang-jwt/jwt/v4"
"time"
)
//var (
// TokenExpired = errors.New("token is timed out, please log in again")
// TokenInvalid = errors.New("token has been invalidated")
// TokenNotValidYet = errors.New("token not active yet")
// TokenMalformed = errors.New("that's not even a token")
// TokenUnknown = errors.New("couldn't handle this token")
//)
type Claims struct {
UID string
Platform string //login platform
jwt.RegisteredClaims
}
func BuildClaims(uid, platform string, ttl int64) Claims {
now := time.Now()
return Claims{
UID: uid,
Platform: platform,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(now.Add(time.Duration(ttl*24) * time.Hour)), //Expiration time
IssuedAt: jwt.NewNumericDate(now), //Issuing time
NotBefore: jwt.NewNumericDate(now), //Begin Effective time
}}
}
func CreateToken(userID string, platformID int32) (string, int64, error) {
claims := BuildClaims(userID, constant.PlatformIDToName(platformID), config.Config.TokenPolicy.AccessExpire)
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString([]byte(config.Config.TokenPolicy.AccessSecret))
if err != nil {
return "", 0, err
}
2021-12-28 10:59:01 +08:00
//remove Invalid token
m, err := commonDB.DB.GetTokenMapByUidPid(userID, constant.PlatformIDToName(platformID))
if err != nil && err != redis.ErrNil {
return "", 0, err
}
var deleteTokenKey []string
for k, v := range m {
2021-12-29 11:31:51 +08:00
_, err = GetClaimFromToken(k)
if err != nil || v != constant.NormalToken {
2021-12-28 10:59:01 +08:00
deleteTokenKey = append(deleteTokenKey, k)
}
}
2021-12-28 17:12:07 +08:00
if len(deleteTokenKey) != 0 {
err = commonDB.DB.DeleteTokenByUidPid(userID, platformID, deleteTokenKey)
if err != nil {
return "", 0, err
}
2021-12-28 10:59:01 +08:00
}
2021-11-25 14:12:52 +08:00
err = commonDB.DB.AddTokenFlag(userID, platformID, tokenString, constant.NormalToken)
if err != nil {
return "", 0, err
}
return tokenString, claims.ExpiresAt.Time.Unix(), err
}
func secret() jwt.Keyfunc {
return func(token *jwt.Token) (interface{}, error) {
return []byte(config.Config.TokenPolicy.AccessSecret), nil
}
}
2021-11-30 15:37:51 +08:00
func GetClaimFromToken(tokensString string) (*Claims, error) {
2021-11-25 14:12:52 +08:00
token, err := jwt.ParseWithClaims(tokensString, &Claims{}, secret())
if err != nil {
if ve, ok := err.(*jwt.ValidationError); ok {
if ve.Errors&jwt.ValidationErrorMalformed != 0 {
return nil, &constant.ErrTokenMalformed
} else if ve.Errors&jwt.ValidationErrorExpired != 0 {
return nil, &constant.ErrTokenExpired
} else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
return nil, &constant.ErrTokenNotValidYet
} else {
return nil, &constant.ErrTokenUnknown
}
} else {
return nil, &constant.ErrTokenNotValidYet
}
} else {
if claims, ok := token.Claims.(*Claims); ok && token.Valid {
2022-04-13 15:29:35 +08:00
//log.NewDebug("", claims.UID, claims.Platform)
2021-11-25 14:12:52 +08:00
return claims, nil
}
return nil, &constant.ErrTokenNotValidYet
}
}
2021-12-23 17:22:49 +08:00
func IsAppManagerAccess(token string, OpUserID string) bool {
2022-03-30 15:52:04 +08:00
claims, err := ParseToken(token, "")
2021-12-23 17:22:49 +08:00
if err != nil {
return false
}
if utils.IsContain(claims.UID, config.Config.Manager.AppManagerUid) && claims.UID == OpUserID {
return true
}
return false
}
2022-04-16 20:10:10 +08:00
func IsManagerUserID(OpUserID string) bool {
2021-12-23 17:22:49 +08:00
if utils.IsContain(OpUserID, config.Config.Manager.AppManagerUid) {
return true
} else {
return false
}
}
func CheckAccess(OpUserID string, OwnerUserID string) bool {
if utils.IsContain(OpUserID, config.Config.Manager.AppManagerUid) {
return true
}
if OpUserID == OwnerUserID {
return true
}
return false
}
2022-03-17 11:57:21 +08:00
func GetUserIDFromToken(token string, operationID string) (bool, string) {
2022-03-30 15:52:04 +08:00
claims, err := ParseToken(token, operationID)
2021-12-23 17:22:49 +08:00
if err != nil {
2022-03-17 11:57:21 +08:00
log.Error(operationID, "ParseToken failed, ", err.Error(), token)
2021-12-23 17:22:49 +08:00
return false, ""
}
return true, claims.UID
}
2022-04-15 19:48:17 +08:00
func ParseTokenGetUserID(token string, operationID string) (error, string) {
claims, err := ParseToken(token, operationID)
if err != nil {
return utils.Wrap(err, ""), ""
}
return nil, claims.UID
}
2022-03-30 15:52:04 +08:00
func ParseToken(tokensString, operationID string) (claims *Claims, err error) {
2021-11-30 15:37:51 +08:00
claims, err = GetClaimFromToken(tokensString)
2021-11-25 14:12:52 +08:00
if err != nil {
2022-03-30 15:52:04 +08:00
log.NewError(operationID, "token validate err", err.Error(), tokensString)
2021-11-25 14:12:52 +08:00
return nil, err
}
2021-11-25 16:09:26 +08:00
2021-11-25 14:12:52 +08:00
m, err := commonDB.DB.GetTokenMapByUidPid(claims.UID, claims.Platform)
if err != nil {
2022-03-30 15:52:04 +08:00
log.NewError(operationID, "get token from redis err", err.Error(), tokensString)
2021-11-25 14:12:52 +08:00
return nil, &constant.ErrTokenInvalid
}
if m == nil {
2022-03-30 15:52:04 +08:00
log.NewError(operationID, "get token from redis err", "m is nil", tokensString)
2021-11-25 14:12:52 +08:00
return nil, &constant.ErrTokenInvalid
}
if v, ok := m[tokensString]; ok {
switch v {
case constant.NormalToken:
2022-03-30 20:04:12 +08:00
log.NewDebug(operationID, "this is normal return", claims)
2021-11-25 14:12:52 +08:00
return claims, nil
case constant.InValidToken:
return nil, &constant.ErrTokenInvalid
case constant.KickedToken:
2022-03-30 20:04:12 +08:00
log.Error(operationID, "this token has been kicked by other same terminal ", constant.ErrTokenKicked)
2022-03-17 11:57:21 +08:00
return nil, &constant.ErrTokenKicked
2021-11-25 14:12:52 +08:00
case constant.ExpiredToken:
return nil, &constant.ErrTokenExpired
2021-11-25 16:37:36 +08:00
default:
return nil, &constant.ErrTokenUnknown
2021-11-25 14:12:52 +08:00
}
}
2022-03-30 20:04:12 +08:00
log.NewError(operationID, "redis token map not find", constant.ErrTokenUnknown)
2021-11-30 15:37:51 +08:00
return nil, &constant.ErrTokenUnknown
2021-11-25 14:12:52 +08:00
}
//func MakeTheTokenInvalid(currentClaims *Claims, platformClass string) (bool, error) {
// storedRedisTokenInterface, err := db.DB.GetPlatformToken(currentClaims.UID, platformClass)
// if err != nil {
// return false, err
// }
// storedRedisPlatformClaims, err := ParseRedisInterfaceToken(storedRedisTokenInterface)
// if err != nil {
// return false, err
// }
// //if issue time less than redis token then make this token invalid
// if currentClaims.IssuedAt.Time.Unix() < storedRedisPlatformClaims.IssuedAt.Time.Unix() {
// return true, constant.TokenInvalid
// }
// return false, nil
//}
func ParseRedisInterfaceToken(redisToken interface{}) (*Claims, error) {
2021-11-30 15:37:51 +08:00
return GetClaimFromToken(string(redisToken.([]uint8)))
2021-11-25 14:12:52 +08:00
}
//Validation token, false means failure, true means successful verification
func VerifyToken(token, uid string) (bool, error) {
2022-03-30 15:52:04 +08:00
claims, err := ParseToken(token, "")
2021-11-25 14:12:52 +08:00
if err != nil {
return false, err
}
if claims.UID != uid {
return false, &constant.ErrTokenUnknown
}
2022-03-17 15:46:32 +08:00
2021-11-25 16:09:26 +08:00
log.NewDebug("", claims.UID, claims.Platform)
2021-11-25 14:12:52 +08:00
return true, nil
}
2022-03-17 15:46:32 +08:00
func WsVerifyToken(token, uid string, platformID string) (bool, error, string) {
2022-03-30 15:52:04 +08:00
claims, err := ParseToken(token, "")
2022-03-17 15:46:32 +08:00
if err != nil {
return false, err, "parse token err"
}
if claims.UID != uid {
return false, &constant.ErrTokenUnknown, "uid is not same to token uid"
}
if claims.Platform != constant.PlatformIDToName(utils.StringToInt32(platformID)) {
return false, &constant.ErrTokenUnknown, "platform is not same to token platform"
}
log.NewDebug("", claims.UID, claims.Platform)
return true, nil, ""
}