fix: rp_caches race condition causing intermittent 403
load_roleperms() was setting self.rp_caches = {} before the async
DB query. During the await, other coroutines saw {} (not None),
skipped the load, and checked permissions against an empty dict,
causing intermittent 403 on random paths.
Fix: build in local dict first, assign atomically when complete.
This commit is contained in:
parent
c776c0b3b5
commit
fbbe011a8d
@ -237,7 +237,9 @@ class UserPermissions:
|
|||||||
if _cache_enabled('rbac') and self.rp_caches is not None and (now - self.rp_cache_loaded_at) < self.rp_cache_ttl:
|
if _cache_enabled('rbac') and self.rp_caches is not None and (now - self.rp_cache_loaded_at) < self.rp_cache_ttl:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.rp_caches = {}
|
# Build in local dict first, assign atomically when complete.
|
||||||
|
# Otherwise other coroutines see {} during the await and get 403.
|
||||||
|
new_caches = {}
|
||||||
sql_all = """select c.id, c.orgtypeid, c.name, b.path
|
sql_all = """select c.id, c.orgtypeid, c.name, b.path
|
||||||
from rolepermission a, permission b, role c
|
from rolepermission a, permission b, role c
|
||||||
where a.permid = b.id
|
where a.permid = b.id
|
||||||
@ -253,9 +255,11 @@ order by c.orgtypeid, c.name"""
|
|||||||
k = 'logined'
|
k = 'logined'
|
||||||
else:
|
else:
|
||||||
k = f'{r.orgtypeid}.{r.name}'
|
k = f'{r.orgtypeid}.{r.name}'
|
||||||
arr = self.rp_caches.get(k, [])
|
arr = new_caches.get(k, [])
|
||||||
arr.append(r.path)
|
arr.append(r.path)
|
||||||
self.rp_caches[k] = arr
|
new_caches[k] = arr
|
||||||
|
# Atomic swap: other coroutines see old cache or fully-loaded new cache, never {}
|
||||||
|
self.rp_caches = new_caches
|
||||||
self.rp_cache_loaded_at = now
|
self.rp_cache_loaded_at = now
|
||||||
|
|
||||||
async def get_userroles(self, sor, userid):
|
async def get_userroles(self, sor, userid):
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user