github.com/polarismesh/polaris@v1.17.8/cache/auth/user.go (about)

     1  /**
     2   * Tencent is pleased to support the open source community by making Polaris available.
     3   *
     4   * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
     5   *
     6   * Licensed under the BSD 3-Clause License (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   * https://opensource.org/licenses/BSD-3-Clause
    11   *
    12   * Unless required by applicable law or agreed to in writing, software distributed
    13   * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    14   * CONDITIONS OF ANY KIND, either express or implied. See the License for the
    15   * specific language governing permissions and limitations under the License.
    16   */
    17  
    18  package auth
    19  
    20  import (
    21  	"fmt"
    22  	"math"
    23  	"sync/atomic"
    24  	"time"
    25  
    26  	"go.uber.org/zap"
    27  	"golang.org/x/sync/singleflight"
    28  
    29  	types "github.com/polarismesh/polaris/cache/api"
    30  	"github.com/polarismesh/polaris/common/model"
    31  	"github.com/polarismesh/polaris/common/utils"
    32  	"github.com/polarismesh/polaris/store"
    33  )
    34  
    35  const (
    36  	NameLinkOwnerTemp = "%s@%s"
    37  )
    38  
    39  type userRefreshResult struct {
    40  	userAdd    int
    41  	userUpdate int
    42  	userDel    int
    43  
    44  	groupAdd    int
    45  	groupUpdate int
    46  	groupDel    int
    47  }
    48  
    49  // userCache 用户信息缓存
    50  type userCache struct {
    51  	*types.BaseCache
    52  
    53  	storage store.Store
    54  
    55  	adminUser atomic.Value
    56  	// userid -> user
    57  	users *utils.SyncMap[string, *model.User]
    58  	// username -> user
    59  	name2Users *utils.SyncMap[string, *model.User]
    60  	// groupid -> group
    61  	groups *utils.SyncMap[string, *model.UserGroupDetail]
    62  	// userid -> groups
    63  	user2Groups *utils.SyncMap[string, *utils.SyncSet[string]]
    64  
    65  	lastUserMtime  int64
    66  	lastGroupMtime int64
    67  
    68  	singleFlight *singleflight.Group
    69  }
    70  
    71  // NewUserCache
    72  func NewUserCache(storage store.Store, cacheMgr types.CacheManager) types.UserCache {
    73  	return &userCache{
    74  		BaseCache: types.NewBaseCache(storage, cacheMgr),
    75  		storage:   storage,
    76  	}
    77  }
    78  
    79  // Initialize
    80  func (uc *userCache) Initialize(_ map[string]interface{}) error {
    81  	uc.users = utils.NewSyncMap[string, *model.User]()
    82  	uc.name2Users = utils.NewSyncMap[string, *model.User]()
    83  	uc.groups = utils.NewSyncMap[string, *model.UserGroupDetail]()
    84  	uc.user2Groups = utils.NewSyncMap[string, *utils.SyncSet[string]]()
    85  	uc.adminUser = atomic.Value{}
    86  	uc.singleFlight = new(singleflight.Group)
    87  	return nil
    88  }
    89  
    90  func (uc *userCache) Update() error {
    91  	// Multiple threads competition, only one thread is updated
    92  	_, err, _ := uc.singleFlight.Do(uc.Name(), func() (interface{}, error) {
    93  		return nil, uc.DoCacheUpdate(uc.Name(), uc.realUpdate)
    94  	})
    95  	return err
    96  }
    97  
    98  func (uc *userCache) realUpdate() (map[string]time.Time, int64, error) {
    99  	// Get all data before a few seconds
   100  	start := time.Now()
   101  	users, err := uc.storage.GetUsersForCache(uc.LastFetchTime(), uc.IsFirstUpdate())
   102  	if err != nil {
   103  		log.Errorf("[Cache][User] update user err: %s", err.Error())
   104  		return nil, -1, err
   105  	}
   106  
   107  	groups, err := uc.storage.GetGroupsForCache(uc.LastFetchTime(), uc.IsFirstUpdate())
   108  	if err != nil {
   109  		log.Errorf("[Cache][Group] update group err: %s", err.Error())
   110  		return nil, -1, err
   111  	}
   112  	lastMimes, refreshRet := uc.setUserAndGroups(users, groups)
   113  
   114  	timeDiff := time.Since(start)
   115  	if timeDiff > time.Second {
   116  		log.Info("[Cache][User] get more user",
   117  			zap.Int("add", refreshRet.userAdd),
   118  			zap.Int("update", refreshRet.userUpdate),
   119  			zap.Int("delete", refreshRet.userDel),
   120  			zap.Time("last", time.Unix(uc.lastUserMtime, 0)), zap.Duration("used", time.Since(start)))
   121  
   122  		log.Info("[Cache][Group] get more group",
   123  			zap.Int("add", refreshRet.groupAdd),
   124  			zap.Int("update", refreshRet.groupUpdate),
   125  			zap.Int("delete", refreshRet.groupDel),
   126  			zap.Time("last", time.Unix(uc.lastGroupMtime, 0)), zap.Duration("used", time.Since(start)))
   127  	}
   128  	return lastMimes, int64(len(users) + len(groups)), nil
   129  }
   130  
   131  func (uc *userCache) setUserAndGroups(users []*model.User,
   132  	groups []*model.UserGroupDetail) (map[string]time.Time, userRefreshResult) {
   133  	ret := userRefreshResult{}
   134  
   135  	ownerSupplier := func(user *model.User) *model.User {
   136  		if user.Type == model.SubAccountUserRole {
   137  			owner, _ := uc.users.Load(user.Owner)
   138  			return owner
   139  		}
   140  		return user
   141  	}
   142  
   143  	lastMimes := map[string]time.Time{}
   144  
   145  	// 更新 users 缓存
   146  	// step 1. 先更新 owner 用户
   147  	uc.handlerUserCacheUpdate(lastMimes, &ret, users, func(user *model.User) bool {
   148  		return user.Type == model.OwnerUserRole
   149  	}, ownerSupplier)
   150  
   151  	// step 2. 更新非 owner 用户
   152  	uc.handlerUserCacheUpdate(lastMimes, &ret, users, func(user *model.User) bool {
   153  		return user.Type == model.SubAccountUserRole
   154  	}, ownerSupplier)
   155  
   156  	uc.handlerGroupCacheUpdate(lastMimes, &ret, groups)
   157  	return lastMimes, ret
   158  }
   159  
   160  // handlerUserCacheUpdate 处理用户信息更新
   161  func (uc *userCache) handlerUserCacheUpdate(lastMimes map[string]time.Time, ret *userRefreshResult, users []*model.User,
   162  	filter func(user *model.User) bool, ownerSupplier func(user *model.User) *model.User) {
   163  
   164  	lastUserMtime := uc.LastMtime("users").Unix()
   165  
   166  	for i := range users {
   167  		user := users[i]
   168  
   169  		lastUserMtime = int64(math.Max(float64(lastUserMtime), float64(user.ModifyTime.Unix())))
   170  
   171  		if user.Type == model.AdminUserRole {
   172  			uc.adminUser.Store(user)
   173  			uc.users.Store(user.ID, user)
   174  			uc.name2Users.Store(fmt.Sprintf(NameLinkOwnerTemp, user.Name, user.Name), user)
   175  			continue
   176  		}
   177  
   178  		if !filter(user) {
   179  			continue
   180  		}
   181  
   182  		owner := ownerSupplier(user)
   183  		if !user.Valid {
   184  			// 删除 user-id -> user 的缓存
   185  			// 删除 username + ownername -> user 的缓存
   186  			// 删除 user-id -> group-ids 的缓存
   187  			uc.users.Delete(user.ID)
   188  			uc.name2Users.Delete(fmt.Sprintf(NameLinkOwnerTemp, owner.Name, user.Name))
   189  			// uc.user2Groups.Delete(user.ID)
   190  			ret.userDel++
   191  		} else {
   192  			if _, ok := uc.users.Load(user.ID); ok {
   193  				ret.userUpdate++
   194  			} else {
   195  				ret.userAdd++
   196  			}
   197  			uc.users.Store(user.ID, user)
   198  			uc.name2Users.Store(fmt.Sprintf(NameLinkOwnerTemp, owner.Name, user.Name), user)
   199  		}
   200  	}
   201  
   202  	lastMimes["users"] = time.Unix(lastUserMtime, 0)
   203  }
   204  
   205  // handlerGroupCacheUpdate 处理用户组信息更新
   206  func (uc *userCache) handlerGroupCacheUpdate(lastMimes map[string]time.Time, ret *userRefreshResult,
   207  	groups []*model.UserGroupDetail) {
   208  
   209  	lastGroupMtime := uc.LastMtime("group").Unix()
   210  
   211  	// 更新 groups 数据信息
   212  	for i := range groups {
   213  		group := groups[i]
   214  
   215  		lastGroupMtime = int64(math.Max(float64(lastGroupMtime), float64(group.ModifyTime.Unix())))
   216  
   217  		if !group.Valid {
   218  			uc.groups.Delete(group.ID)
   219  			ret.groupDel++
   220  		} else {
   221  			var oldGroup *model.UserGroupDetail
   222  			if oldVal, ok := uc.groups.Load(group.ID); ok {
   223  				ret.groupUpdate++
   224  				oldGroup = oldVal
   225  			} else {
   226  				ret.groupAdd++
   227  			}
   228  			uc.groups.Store(group.ID, group)
   229  
   230  			if oldGroup != nil {
   231  				oldUserIds := oldGroup.UserIds
   232  				delUserIds := make([]string, 0, 4)
   233  				for oldUserId := range oldUserIds {
   234  					if _, ok := group.UserIds[oldUserId]; !ok {
   235  						delUserIds = append(delUserIds, oldUserId)
   236  					}
   237  				}
   238  
   239  				for di := range delUserIds {
   240  					waitDel := delUserIds[di]
   241  					if oldGids, ok := uc.user2Groups.Load(waitDel); ok {
   242  						oldGids.Remove(group.ID)
   243  					}
   244  				}
   245  			}
   246  
   247  			for uid := range group.UserIds {
   248  				_, exist := uc.user2Groups.Load(uid)
   249  				if !exist {
   250  					uc.user2Groups.Store(uid, utils.NewSyncSet[string]())
   251  				}
   252  				val, _ := uc.user2Groups.Load(uid)
   253  				val.Add(group.ID)
   254  			}
   255  		}
   256  	}
   257  
   258  	lastMimes["group"] = time.Unix(lastGroupMtime, 0)
   259  }
   260  
   261  func (uc *userCache) Clear() error {
   262  	uc.BaseCache.Clear()
   263  	uc.users = utils.NewSyncMap[string, *model.User]()
   264  	uc.name2Users = utils.NewSyncMap[string, *model.User]()
   265  	uc.groups = utils.NewSyncMap[string, *model.UserGroupDetail]()
   266  	uc.user2Groups = utils.NewSyncMap[string, *utils.SyncSet[string]]()
   267  	uc.adminUser = atomic.Value{}
   268  	uc.lastUserMtime = 0
   269  	uc.lastGroupMtime = 0
   270  	return nil
   271  }
   272  
   273  func (uc *userCache) Name() string {
   274  	return types.UsersName
   275  }
   276  
   277  // GetAdmin 获取管理员数据信息
   278  func (uc *userCache) GetAdmin() *model.User {
   279  	val := uc.adminUser.Load()
   280  	if val == nil {
   281  		return nil
   282  	}
   283  
   284  	return val.(*model.User)
   285  }
   286  
   287  // IsOwner 判断当前用户是否是 owner 角色
   288  func (uc *userCache) IsOwner(id string) bool {
   289  	val, ok := uc.users.Load(id)
   290  	if !ok {
   291  		return false
   292  	}
   293  	ut := val.Type
   294  	return ut == model.AdminUserRole || ut == model.OwnerUserRole
   295  }
   296  
   297  func (uc *userCache) IsUserInGroup(userId, groupId string) bool {
   298  	group := uc.GetGroup(groupId)
   299  	if group == nil {
   300  		return false
   301  	}
   302  	_, exist := group.UserIds[userId]
   303  	return exist
   304  }
   305  
   306  // GetUserByID 根据用户ID获取用户缓存对象
   307  func (uc *userCache) GetUserByID(id string) *model.User {
   308  	if id == "" {
   309  		return nil
   310  	}
   311  
   312  	val, ok := uc.users.Load(id)
   313  	if !ok {
   314  		return nil
   315  	}
   316  	return val
   317  }
   318  
   319  // GetUserByName 通过用户 name 以及 owner 获取用户缓存对象
   320  func (uc *userCache) GetUserByName(name, ownerName string) *model.User {
   321  	val, ok := uc.name2Users.Load(fmt.Sprintf(NameLinkOwnerTemp, ownerName, name))
   322  
   323  	if !ok {
   324  		return nil
   325  	}
   326  	return val
   327  }
   328  
   329  // GetGroup 通过用户组ID获取用户组缓存对象
   330  func (uc *userCache) GetGroup(id string) *model.UserGroupDetail {
   331  	if id == "" {
   332  		return nil
   333  	}
   334  	val, ok := uc.groups.Load(id)
   335  
   336  	if !ok {
   337  		return nil
   338  	}
   339  
   340  	return val
   341  }
   342  
   343  // GetUserLinkGroupIds 根据用户ID查询该用户关联的用户组ID列表
   344  func (uc *userCache) GetUserLinkGroupIds(userId string) []string {
   345  	if userId == "" {
   346  		return nil
   347  	}
   348  	val, ok := uc.user2Groups.Load(userId)
   349  	if !ok {
   350  		return nil
   351  	}
   352  	return val.ToSlice()
   353  }