有更好的方法吗? MySQL的

时间:2012-02-04 07:34:46

标签: mysql database-design stored-procedures

我正在将权限系统从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

1 个答案:

答案 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,这意味着将首先显示用户权限。