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 }