diff --git a/rbac/init.py b/rbac/init.py
index 0e22547..c699557 100644
--- a/rbac/init.py
+++ b/rbac/init.py
@@ -1,31 +1,84 @@
from ahserver.auth_api import AuthAPI
from ahserver.serverenv import ServerEnv
-from sqlor.dbpools import DBPools
from .orgs import (
get_platform_providers
)
from .userperm import UserPermissions
-from .user_stats import get_user_stats
-from .rbac_tools import (
- query_path_roles,
- scan_unauth_files
-)
from rbac.check_perm import (
- objcheckperm,
+ objcheckperm,
get_org_users,
sor_get_org_users,
- checkUserPassword,
- register_user,
- register_auth_method,
- create_org,
+ checkUserPassword,
+ register_user,
+ register_auth_method,
+ create_org,
create_user
)
from rbac.set_role_perms import (
sor_add_user_roles,
- set_role_perm,
+ set_role_perm,
set_role_perms
)
-from appPublic.log import debug
+from sqlor.dbpools import DBPools
+
+
+def _get_rbac_dbname():
+ env = ServerEnv()
+ return env.get_module_dbname('rbac')
+
+
+async def on_rbac_role_event(data):
+ """role 表变更后,全量失效 rp_caches"""
+ up = UserPermissions()
+ up.invalidate_rp_cache()
+
+
+async def on_rbac_userrole_event(data):
+ """userrole 表变更后,精确失效对应用户的 ur_caches"""
+ ns = data.get('ns', {})
+ userid = ns.get('userid')
+ up = UserPermissions()
+ if userid:
+ up.invalidate_user_cache(userid)
+ else:
+ up.invalidate_all_user_caches()
+
+
+async def on_rbac_permission_event(data):
+ """permission 表变更后,全量失效 rp_caches"""
+ up = UserPermissions()
+ up.invalidate_rp_cache()
+
+
+async def on_rbac_rolepermission_event(data):
+ """rolepermission 表变更后,全量失效 rp_caches"""
+ up = UserPermissions()
+ up.invalidate_rp_cache()
+
+
+def register_rbac_event_listeners():
+ db = DBPools()
+ dbname = _get_rbac_dbname()
+
+ # role 表
+ db.bind(f'{dbname}:role:c:after', on_rbac_role_event)
+ db.bind(f'{dbname}:role:u:after', on_rbac_role_event)
+ db.bind(f'{dbname}:role:d:after', on_rbac_role_event)
+
+ # userrole 表
+ db.bind(f'{dbname}:userrole:c:after', on_rbac_userrole_event)
+ db.bind(f'{dbname}:userrole:u:after', on_rbac_userrole_event)
+ db.bind(f'{dbname}:userrole:d:after', on_rbac_userrole_event)
+
+ # permission 表
+ db.bind(f'{dbname}:permission:c:after', on_rbac_permission_event)
+ db.bind(f'{dbname}:permission:u:after', on_rbac_permission_event)
+ db.bind(f'{dbname}:permission:d:after', on_rbac_permission_event)
+
+ # rolepermission 表
+ db.bind(f'{dbname}:rolepermission:c:after', on_rbac_rolepermission_event)
+ db.bind(f'{dbname}:rolepermission:u:after', on_rbac_rolepermission_event)
+ db.bind(f'{dbname}:rolepermission:d:after', on_rbac_rolepermission_event)
async def get_owner_orgid(*args, **kw):
return '0'
@@ -33,37 +86,6 @@ async def get_owner_orgid(*args, **kw):
async def sor_get_owner_orgid(sor, orgid):
return '0'
-def _bind_rbac_events(dbpools, dbname, up):
- """Bind database events to RBAC cache invalidation handlers.
-
- Events are dispatched by sqlor after C/U/D operations.
- Format: {dbname}:{tablename}:{c|u|d}:after
- """
- bindings = [
- # users table: invalidate specific user cache on C/U/D
- (f'{dbname}.users:c:after', up.on_user_create),
- (f'{dbname}.users:u:after', up.on_user_update),
- (f'{dbname}.users:d:after', up.on_user_delete),
- # rolepermission table: invalidate role-permission cache on any change
- (f'{dbname}.rolepermission:c:after', up.on_rolepermission_change),
- (f'{dbname}.rolepermission:u:after', up.on_rolepermission_change),
- (f'{dbname}.rolepermission:d:after', up.on_rolepermission_change),
- # permission table: invalidate role-permission cache on update
- (f'{dbname}.permission:u:after', up.on_permission_change),
- # role table: invalidate ALL caches (affects all users)
- (f'{dbname}.role:c:after', up.on_role_change),
- (f'{dbname}.role:u:after', up.on_role_change),
- (f'{dbname}.role:d:after', up.on_role_change),
- # userrole table: invalidate specific user cache based on userid
- (f'{dbname}.userrole:c:after', up.on_userrole_change),
- (f'{dbname}.userrole:u:after', up.on_userrole_change),
- (f'{dbname}.userrole:d:after', up.on_userrole_change),
- ]
- for event_name, handler in bindings:
- dbpools.bind(event_name, handler)
- debug(f'RBAC event bound: {event_name}')
-
-
def load_rbac():
AuthAPI.checkUserPermission = objcheckperm
env = ServerEnv()
@@ -81,19 +103,8 @@ def load_rbac():
env.sor_get_org_users = sor_get_org_users
env.get_owner_orgid = get_owner_orgid
env.sor_add_user_roles = sor_add_user_roles
- env.get_user_stats = get_user_stats
- env.query_path_roles = query_path_roles
- env.scan_unauth_files = scan_unauth_files
# Cache invalidation methods for use after role/permission changes
env.invalidate_user_perm_cache = env.userpermissions.invalidate_user_cache
env.invalidate_all_perm_caches = env.userpermissions.invalidate_all_user_caches
env.invalidate_role_perm_cache = env.userpermissions.invalidate_rp_cache
-
- # Bind database events for automatic cache invalidation
- dbpools = DBPools()
- dbname = env.get_module_dbname('rbac')
- if dbname:
- _bind_rbac_events(dbpools, dbname, env.userpermissions)
- debug(f'RBAC event listeners bound for database: {dbname}')
- else:
- debug('RBAC event listeners skipped: no database configured for rbac module')
+ register_rbac_event_listeners()
diff --git a/wwwroot/index.ui b/wwwroot/index.ui
deleted file mode 100644
index aff2170..0000000
--- a/wwwroot/index.ui
+++ /dev/null
@@ -1,212 +0,0 @@
-{% set roles = get_user_roles(get_user()) %}
-{
- "widgettype": "VBox",
- "options": {
- "width": "100%",
- "height": "100%",
- "padding": "0",
- "bgcolor": "#0B1120"
- },
- "subwidgets": [
- {
- "widgettype": "HBox",
- "options": {
- "width": "100%",
- "alignItems": "center",
- "marginBottom": "24px"
- },
- "subwidgets": [
- {
- "widgettype": "Title2",
- "options": {
- "text": "用户与权限",
- "color": "#F1F5F9",
- "fontWeight": "700"
- }
- },
- {
- "widgettype": "Filler"
- },
- {
- "widgettype": "Text",
- "options": {
- "text": "用户管理、角色权限与安全审计",
- "fontSize": "14px",
- "color": "#64748B"
- }
- }
- ]
- },
-{% if 'reseller.admin' in roles or 'owner.superuser' in roles %}
- {
- "widgettype": "ResponsableBox",
- "options": {
- "gap": "16px",
- "minWidth": "250px",
- "marginBottom": "24px"
- },
- "subwidgets": [
- {
- "widgettype": "VBox",
- "options": {
- "bgcolor": "#1E293B",
- "padding": "24px",
- "borderRadius": "12px",
- "border": "1px solid #334155",
- "cursor": "pointer"
- },
- "binds": [
- {
- "wid": "self",
- "event": "click",
- "actiontype": "urlwidget",
- "target": "app.rbac_content",
- "options": {
- "url": "{{entire_url('/rbac/users')}}"
- },
- "mode": "replace"
- }
- ],
- "subwidgets": [
- {
- "widgettype": "Svg",
- "options": {
- "svg": "",
- "width": "36px",
- "height": "36px",
- "marginBottom": "16px"
- }
- },
- {
- "widgettype": "Title4",
- "options": {
- "text": "用户管理",
- "color": "#F1F5F9",
- "fontWeight": "600",
- "marginBottom": "8px"
- }
- },
- {
- "widgettype": "Text",
- "options": {
- "text": "管理系统用户、角色分配与账户信息",
- "fontSize": "14px",
- "color": "#94A3B8"
- }
- }
- ]
- },
- {
- "widgettype": "VBox",
- "options": {
- "bgcolor": "#1E293B",
- "padding": "24px",
- "borderRadius": "12px",
- "border": "1px solid #334155",
- "cursor": "pointer"
- },
- "binds": [
- {
- "wid": "self",
- "event": "click",
- "actiontype": "urlwidget",
- "target": "app.rbac_content",
- "options": {
- "url": "{{entire_url('/rbac/list_path_roles.ui')}}"
- },
- "mode": "replace"
- }
- ],
- "subwidgets": [
- {
- "widgettype": "Svg",
- "options": {
- "svg": "",
- "width": "36px",
- "height": "36px",
- "marginBottom": "16px"
- }
- },
- {
- "widgettype": "Title4",
- "options": {
- "text": "路径权限角色",
- "color": "#F1F5F9",
- "fontWeight": "600",
- "marginBottom": "8px"
- }
- },
- {
- "widgettype": "Text",
- "options": {
- "text": "查询各路径绑定的角色与权限配置",
- "fontSize": "14px",
- "color": "#94A3B8"
- }
- }
- ]
- },
- {
- "widgettype": "VBox",
- "options": {
- "bgcolor": "#1E293B",
- "padding": "24px",
- "borderRadius": "12px",
- "border": "1px solid #334155",
- "cursor": "pointer"
- },
- "binds": [
- {
- "wid": "self",
- "event": "click",
- "actiontype": "urlwidget",
- "target": "app.rbac_content",
- "options": {
- "url": "{{entire_url('/rbac/find_unauth_files.dspy')}}"
- },
- "mode": "replace"
- }
- ],
- "subwidgets": [
- {
- "widgettype": "Svg",
- "options": {
- "svg": "",
- "width": "36px",
- "height": "36px",
- "marginBottom": "16px"
- }
- },
- {
- "widgettype": "Title4",
- "options": {
- "text": "扫描未授权文件",
- "color": "#F1F5F9",
- "fontWeight": "600",
- "marginBottom": "8px"
- }
- },
- {
- "widgettype": "Text",
- "options": {
- "text": "检测未配置RBAC权限的页面文件",
- "fontSize": "14px",
- "color": "#94A3B8"
- }
- }
- ]
- }
- ]
- },
-{% endif %}
- {
- "widgettype": "VBox",
- "id": "rbac_content",
- "css": "filler",
- "options": {
- "width": "100%",
- "overflowY": "auto"
- }
- }
- ]
-}
diff --git a/wwwroot/index.ui b/wwwroot/index.ui
new file mode 120000
index 0000000..235e300
--- /dev/null
+++ b/wwwroot/index.ui
@@ -0,0 +1 @@
+/home/hermesai/repos/rbac/wwwroot/index.ui
\ No newline at end of file
diff --git a/wwwroot/user/logout.dspy b/wwwroot/user/logout.dspy
index 7436688..153336b 100644
--- a/wwwroot/user/logout.dspy
+++ b/wwwroot/user/logout.dspy
@@ -1,9 +1,38 @@
await forget_user()
return {
- "widgettype":"Text",
- "options":{
- "otext":"logout success",
- "i18n":True,
- }
+ "widgettype": "VBox",
+ "options": {
+ "padding": "24px",
+ "alignItems": "center"
+ },
+ "subwidgets": [
+ {
+ "widgettype": "Text",
+ "options": {
+ "otext": "logout success",
+ "i18n": True,
+ "fontSize": "16px",
+ "marginBottom": "16px"
+ }
+ },
+ {
+ "widgettype": "Button",
+ "options": {
+ "label": "刷新页面",
+ "bgcolor": "#3B82F6",
+ "color": "white",
+ "padding": "8px 24px",
+ "borderRadius": "6px"
+ },
+ "binds": [
+ {
+ "wid": "self",
+ "event": "click",
+ "actiontype": "script",
+ "target": "self",
+ "script": "location.reload()"
+ }
+ ]
+ }
+ ]
}
-