Files
open-im-server/pkg/common/storage/controller/auth.go
T

234 lines
6.9 KiB
Go
Raw Normal View History

2023-06-30 09:45:02 +08:00
package controller
import (
"context"
2024-03-04 21:32:07 +08:00
"github.com/golang-jwt/jwt/v4"
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
2024-11-14 14:35:18 +08:00
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache"
2024-11-14 14:35:18 +08:00
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey"
2024-04-19 22:23:08 +08:00
"github.com/openimsdk/protocol/constant"
"github.com/openimsdk/tools/errs"
2024-11-14 14:35:18 +08:00
"github.com/openimsdk/tools/log"
2024-04-19 22:23:08 +08:00
"github.com/openimsdk/tools/tokenverify"
2023-06-30 09:45:02 +08:00
)
type AuthDatabase interface {
// If the result is empty, no error is returned.
2023-06-30 09:45:02 +08:00
GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error)
// Create token
2023-06-30 09:45:02 +08:00
CreateToken(ctx context.Context, userID string, platformID int) (string, error)
2024-04-19 22:23:08 +08:00
2024-10-24 15:02:44 +08:00
BatchSetTokenMapByUidPid(ctx context.Context, tokens []string) error
2024-04-19 22:23:08 +08:00
SetTokenMapByUidPid(ctx context.Context, userID string, platformID int, m map[string]int) error
2023-06-30 09:45:02 +08:00
}
2024-10-24 15:02:44 +08:00
type multiLoginConfig struct {
2024-11-22 15:49:16 +08:00
Policy int
MaxNumOneEnd int
2024-10-24 15:02:44 +08:00
}
2023-06-30 09:45:02 +08:00
type authDatabase struct {
2024-10-24 15:02:44 +08:00
cache cache.TokenModel
accessSecret string
accessExpire int64
multiLogin multiLoginConfig
2024-11-22 12:25:28 +08:00
adminUserIDs []string
2023-06-30 09:45:02 +08:00
}
2024-11-22 12:25:28 +08:00
func NewAuthDatabase(cache cache.TokenModel, accessSecret string, accessExpire int64, multiLogin config.MultiLogin, adminUserIDs []string) AuthDatabase {
2024-10-24 15:02:44 +08:00
return &authDatabase{cache: cache, accessSecret: accessSecret, accessExpire: accessExpire, multiLogin: multiLoginConfig{
Policy: multiLogin.Policy,
MaxNumOneEnd: multiLogin.MaxNumOneEnd,
2024-11-22 15:49:16 +08:00
},
adminUserIDs: adminUserIDs,
2024-11-22 12:25:28 +08:00
}
2023-06-30 09:45:02 +08:00
}
// If the result is empty.
func (a *authDatabase) GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error) {
2023-06-30 09:45:02 +08:00
return a.cache.GetTokensWithoutError(ctx, userID, platformID)
}
2024-04-19 22:23:08 +08:00
func (a *authDatabase) SetTokenMapByUidPid(ctx context.Context, userID string, platformID int, m map[string]int) error {
return a.cache.SetTokenMapByUidPid(ctx, userID, platformID, m)
}
2024-10-24 15:02:44 +08:00
func (a *authDatabase) BatchSetTokenMapByUidPid(ctx context.Context, tokens []string) error {
setMap := make(map[string]map[string]any)
2024-10-24 15:02:44 +08:00
for _, token := range tokens {
claims, err := tokenverify.GetClaimFromToken(token, authverify.Secret(a.accessSecret))
if err != nil {
continue
}
key := cachekey.GetTokenKey(claims.UserID, claims.PlatformID)
if v, ok := setMap[key]; ok {
v[token] = constant.KickedToken
2024-10-24 15:02:44 +08:00
} else {
setMap[key] = map[string]any{
token: constant.KickedToken,
2024-10-24 15:02:44 +08:00
}
}
}
if err := a.cache.BatchSetTokenMapByUidPid(ctx, setMap); err != nil {
return err
}
return nil
}
// Create Token.
2023-06-30 09:45:02 +08:00
func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformID int) (string, error) {
tokens, err := a.cache.GetAllTokensWithoutError(ctx, userID)
if err != nil {
return "", err
}
2024-11-22 12:25:28 +08:00
deleteTokenKey, kickedTokenKey, err := a.checkToken(ctx, tokens, platformID)
if err != nil {
return "", err
}
if len(deleteTokenKey) != 0 {
err = a.cache.DeleteTokenByUidPid(ctx, userID, platformID, deleteTokenKey)
2024-11-22 12:25:28 +08:00
if err != nil {
return "", err
}
}
if len(kickedTokenKey) != 0 {
for _, k := range kickedTokenKey {
err := a.cache.SetTokenFlagEx(ctx, userID, platformID, k, constant.KickedToken)
2024-09-25 11:05:48 +08:00
if err != nil {
return "", err
}
log.ZDebug(ctx, "kicked token in create token", "token", k)
2024-09-25 11:05:48 +08:00
}
}
2024-02-26 10:55:36 +08:00
2023-06-30 09:45:02 +08:00
claims := tokenverify.BuildClaims(userID, platformID, a.accessExpire)
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString([]byte(a.accessSecret))
if err != nil {
2024-04-19 22:23:08 +08:00
return "", errs.WrapMsg(err, "token.SignedString")
2023-06-30 09:45:02 +08:00
}
if err = a.cache.SetTokenFlagEx(ctx, userID, platformID, tokenString, constant.NormalToken); err != nil {
return "", err
}
2024-11-22 12:25:28 +08:00
return tokenString, nil
2023-06-30 09:45:02 +08:00
}
2024-09-25 11:05:48 +08:00
2024-10-24 15:02:44 +08:00
func (a *authDatabase) checkToken(ctx context.Context, tokens map[int]map[string]int, platformID int) ([]string, []string, error) {
// todo: Move the logic for handling old data to another location.
var (
loginTokenMap = make(map[int][]string) // The length of the value of the map must be greater than 0
deleteToken = make([]string, 0)
kickToken = make([]string, 0)
adminToken = make([]string, 0)
unkickTerminal = ""
)
for plfID, tks := range tokens {
for k, v := range tks {
_, err := tokenverify.GetClaimFromToken(k, authverify.Secret(a.accessSecret))
if err != nil || v != constant.NormalToken {
deleteToken = append(deleteToken, k)
} else {
if plfID != constant.AdminPlatformID {
loginTokenMap[plfID] = append(loginTokenMap[plfID], k)
} else {
adminToken = append(adminToken, k)
}
}
}
}
switch a.multiLogin.Policy {
2024-09-25 11:05:48 +08:00
case constant.DefalutNotKick:
2024-10-24 15:02:44 +08:00
for plt, ts := range loginTokenMap {
l := len(ts)
if platformID == plt {
l++
}
limit := a.multiLogin.MaxNumOneEnd
if l > limit {
kickToken = append(kickToken, ts[:l-limit]...)
}
2024-09-25 11:05:48 +08:00
}
case constant.AllLoginButSameTermKick:
2024-10-24 15:02:44 +08:00
for plt, ts := range loginTokenMap {
kickToken = append(kickToken, ts[:len(ts)-1]...)
if plt == platformID {
kickToken = append(kickToken, ts[len(ts)-1])
}
}
case constant.PCAndOther:
2024-11-01 14:49:31 +08:00
unkickTerminal = constant.TerminalPC
2024-10-24 15:02:44 +08:00
if constant.PlatformIDToClass(platformID) != unkickTerminal {
for plt, ts := range loginTokenMap {
if constant.PlatformIDToClass(plt) != unkickTerminal {
kickToken = append(kickToken, ts...)
}
}
} else {
var (
preKick []string
isReserve = true
)
for plt, ts := range loginTokenMap {
if constant.PlatformIDToClass(plt) != unkickTerminal {
// Keep a token from another end
if isReserve {
isReserve = false
kickToken = append(kickToken, ts[:len(ts)-1]...)
preKick = append(preKick, ts[len(ts)-1])
continue
} else {
// Prioritize keeping Android
if plt == constant.AndroidPlatformID {
kickToken = append(kickToken, preKick...)
kickToken = append(kickToken, ts[:len(ts)-1]...)
} else {
kickToken = append(kickToken, ts...)
}
}
}
}
}
2024-11-01 14:49:31 +08:00
case constant.AllLoginButSameClassKick:
2024-10-24 15:02:44 +08:00
var (
2024-11-01 14:49:31 +08:00
reserved = make(map[string]struct{})
2024-10-24 15:02:44 +08:00
)
for plt, ts := range loginTokenMap {
if constant.PlatformIDToClass(plt) == constant.PlatformIDToClass(platformID) {
kickToken = append(kickToken, ts...)
} else {
2024-11-01 14:49:31 +08:00
if _, ok := reserved[constant.PlatformIDToClass(plt)]; !ok {
reserved[constant.PlatformIDToClass(plt)] = struct{}{}
2024-10-24 15:02:44 +08:00
kickToken = append(kickToken, ts[:len(ts)-1]...)
continue
} else {
kickToken = append(kickToken, ts...)
}
}
}
2024-09-25 11:05:48 +08:00
default:
2024-10-24 15:02:44 +08:00
return nil, nil, errs.New("unknown multiLogin policy").Wrap()
}
2024-11-22 12:25:28 +08:00
//var adminTokenMaxNum = a.multiLogin.MaxNumOneEnd
//l := len(adminToken)
//if platformID == constant.AdminPlatformID {
// l++
//}
//if l > adminTokenMaxNum {
// kickToken = append(kickToken, adminToken[:l-adminTokenMaxNum]...)
//}
if platformID == constant.AdminPlatformID {
kickToken = append(kickToken, adminToken...)
}
2024-10-24 15:02:44 +08:00
return deleteToken, kickToken, nil
2024-09-25 11:05:48 +08:00
}