我正在将权限系统从PHP迁移到MySQL存储过程,因此我可以将该网站放在不同的设备上。
我的权限系统的工作原理如下: 动作是用户可以做的事情。 (等上传照片) 用户可以拥有各自的权限,可以通过角色设置权限,也可以只设置全局权限。 拒绝权限接管允许权限。 为用户设置的权限将覆盖所有其他权限。
我的桌子看起来像这样
每次操作
ACL_Actions:
ActionID | Default_DOA
每个角色
ACL_Roles:
RoleID | Name_Of_Role
为角色中的用户设置操作权限
ACL_Role_Actions:
ID | RoleID | ActionID | Role_DOA
将用户置于角色
ACL_Role_Users:
ID | RoleID | UserID
适用于每位用户
ACL_Users:
UserID | Details
允许用户定义操作权限
ACL_User_Actions:
ID | ActionID | UserID | User_DOA
这些只是表格的一部分,而DOA代表DenyOrAllow。
DOA字段是位。 0 = Deny, 1 = Allow
现在回答我的问题。这个存储过程是我能做到的最佳方式吗? 我正在尝试为操作加载用户权限。
BEGIN
DECLARE current_doa INT;
DECLARE action_id INT;
DECLARE done INT DEFAULT 0;
DECLARE cur1 CURSOR FOR SELECT ActionID, User_DOA FROM ACL_User_Actions WHERE UserID = euser_id;
DECLARE cur2 CURSOR FOR SELECT ActioNID, Role_DOA FROM ACL_Role_Actions WHERE RoleID IN (SELECT RoleID FROM ACL_Role_Users WHERE UserID = euser_id);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
DROP TEMPORARY TABLE IF EXISTS user_roles;
CREATE TEMPORARY TABLE user_roles
SELECT ACL_Actions.ActionID as ActionID, ACL_Actions.Default_DOA as DOA
From ACL_Actions;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO action_id, current_doa;
IF done THEN
LEAVE read_loop;
END IF;
IF current_doa = 0 THEN
UPDATE user_roles SET DOA = current_doa WHERE ActionID = action_id;
END IF;
END LOOP;
CLOSE cur1;
SET done = 0;
OPEN cur2;
read_loop: LOOP
FETCH cur2 INTO action_id, current_doa;
IF done THEN
LEAVE read_loop;
END IF;
UPDATE user_roles SET DOA = current_doa WHERE ActionID = action_id;
END LOOP;
CLOSE cur2;
SELECT * FROM user_roles;
END
答案 0 :(得分:2)
请注意,以下表不需要id列,因此请删除它们。至少使相关列UNIQUE NOT NULL。显然,对于重复项,数据毫无意义,因为例如,您可以为同一用户/操作同时允许和拒绝行。
ACL_Role_Actions :: ID | RoleID | ActionID | Role_DOA
=> PK是(RoleID,ActionID)
ACL_Role_Users: ID | RoleID |用户ID
=> PK是(UserID,RoleID)
ACL_User_Actions: ID | ActionID |用户ID | User_DOA
=> PK是(UserID,ActionID)
由于您有一个用户到角色表,这意味着用户可以是多个角色的成员,但您没有在角色之间指定优先级。如果用户是允许操作X的角色A的成员,并且拒绝操作X的角色B,则行为是未定义的。所以你需要添加一个"优先级"对于角色表的列,我将其定义为正整数,其中0具有最高优先级。在Roles表中,priority必须是UNIQUE。
我的第一个想法是在两个权限表之间使用FULL OUTER JOIN,但mysql不支持。
我的第二个想法是UNION用户/角色权限查询的结果(首先放置用户权限)并使用窗口函数(FIRST()OVER())来获取覆盖其他行的第一行,但MySQL没有&# 39;支持那个。
尝试#1:
SELECT ActionID, GROUP_CONCAT(doa ORDER BY priority) FROM (
SELECT NULL as priority, ActionID, User_DOA doa FROM ACL_User_Actions WHERE UserID = euser_id;
UNION ALL
SELECT priority, ActioNID, Role_DOA doa FROM ACL_Role_Actions JOIN ACL_Role_Users USING (RoleID) WHERE UserID = euser_id
) foo GROUP BY ActioNID
GROUP_CONCAT(User_DOA)将返回" 01"如果user = deny和role = allow,则只需从substr()中取出第一个char。请注意,ORDER BY优先级首先放置NULL,这意味着将首先显示用户权限。