6

问题:

我对 mySQL 相当陌生,我什至不知道从哪里开始。我想知道如何编写一个简单的函数,该函数根据分布在许多表中的值返回真或假。

细节:

这是我的表格的相关部分(所有引擎都是innodb)。当您继续阅读时,您将看到数据库只是存储用户、组、文件以及这些用户/组的这些文件的权限。

用户表

CREATE TABLE IF NOT EXISTS USER
(
   ID                 INT NOT NULL auto_increment,

   PRIMARY KEY(ID)
)

组表:

CREATE TABLE IF NOT EXISTS GROUP
(
   ID           INT NOT NULL AUTO_INCREMENT,

   PRIMARY KEY(ID)
)

组成员表:

CREATE TABLE IF NOT EXISTS GROUPMEMBERSHIP
(
   ID           INT NOT NULL AUTO_INCREMENT,
   USERID       INT NOT NULL,
   GROUPID      INT NOT NULL,

   UNIQUE ( USERID, GROUPID ),
   PRIMARY KEY(ID),
   FOREIGN KEY (USERID) REFERENCES USER(ID),
   FOREIGN KEY (GROUPID) REFERENCES GROUP(ID)
)

FILE 表:(R、W、X,用于other

CREATE TABLE IF NOT EXISTS FILE
(
   ID                 INT NOT NULL AUTO_INCREMENT,
   READ               BOOLEAN DEFAULT FALSE,
   WRITE              BOOLEAN DEFAULT FALSE,
   EXECUTE            BOOLEAN DEFAULT FALSE,

   PRIMARY KEY(ID)
)

文件用户权限表:

CREATE TABLE IF NOT EXISTS FILEUSERPERMISSIONS
(
   ID           INT NOT NULL AUTO_INCREMENT,
   FILEID       INT NOT NULL,
   USERID       INT NOT NULL,
   READ         BOOLEAN DEFAULT FALSE,
   WRITE        BOOLEAN DEFAULT FALSE,
   EXECUTE      BOOLEAN DEFAULT FALSE,

   UNIQUE (FILEID, USERID),
   PRIMARY KEY(ID),
   FOREIGN KEY (FILEID) REFERENCES FILE(ID),
   FOREIGN KEY (USERID) REFERENCES USER(ID)
)

文件组权限表:

CREATE TABLE IF NOT EXISTS FILEGROUPPERMISSIONS
(
   ID           INT NOT NULL AUTO_INCREMENT,
   FILEID       INT NOT NULL,
   GROUPID      INT NOT NULL,
   READ         BOOLEAN DEFAULT FALSE,
   WRITE        BOOLEAN DEFAULT FALSE,
   EXECUTE      BOOLEAN DEFAULT FALSE,

   UNIQUE (FILEID, GROUPID),
   PRIMARY KEY(ID),
   FOREIGN KEY (FILEID) REFERENCES FILE(ID),
   FOREIGN KEY (GROUPID) REFERENCES GROUP(ID)
)

hasPermission函数:

DELIMITER $$
DROP FUNCTION IF EXISTS hasPermission$$
CREATE FUNCTION hasPermission(fileID INT, userID INT)
RETURNS BOOLEAN
BEGIN
   ???
END$$
DELIMITER ;

我将如何进行,或者至少我从哪里开始编写hasPermission函数,以便在这样查询时:

SELECT hasPermission( 123, 456)

它执行以下操作:

  1. 检查文件 123 是否可读other
  2. 检查用户 456 是否对文件 123 具有读取权限
  3. 检查用户 456 是否在对文件 123 具有读取权限的某个组中

第一个是微不足道三者中最琐碎的。第二个把我难住了。第三个对我来说是一个概念障碍。除此之外,我显然必须检查用户和/或文件是否存在。

请善待,因为我是 MySQL 的新手。

谢谢先进

4

3 回答 3

2
  1. 检查文件 123 是否可读other

    你说这很简单,但为了完整起见:

    SELECT READ
    FROM FILE
    WHERE ID = 123;
    
  2. 检查用户 456 是否对文件 123 具有读取权限

    您可以通过表中的类似查找来执行此操作FILEUSERPERMISSIONS

    SELECT READ
    FROM FILEUSERPERMISSIONS
    WHERE FILEID = 123 AND USERID = 456;
    
  3. 检查用户 456 是否在对文件 123 具有读取权限的某个组中

    为此,您需要加入表:GROUP MEMBERSHIPFILE GROUP PERMISSIONS

    SELECT READ
    FROM FILEGROUPPERMISSIONS JOIN GROUPMEMBERSHIP USING (GROUPID)
    WHERE FILEID = 123 AND USERID = 456;
    

要将这些组合在一起,您可以执行以下操作:

SELECT
   (SELECT READ FROM FILE WHERE ID = 123)
OR (SELECT READ FROM FILEUSERPERMISSIONS WHERE FILEID = 123 AND USERID = 456)
OR (SELECT READ FROM FILEGROUPPERMISSIONS JOIN GROUPMEMBERSHIP USING (GROUPID)
    WHERE FILEID = 123 AND USERID = 456);
于 2012-04-25T09:07:17.057 回答
2

检查文件的权限。我可能会这样做:

SELECT
    (
        CASE WHEN EXISTS
            (
                SELECT
                    NULL
                FROM
                    FILE
                WHERE EXISTS
                    (
                        SELECT
                            NULL
                        FROM
                            USER
                            JOIN GROUPMEMBERSHIP
                                ON GROUPMEMBERSHIP.USERID=USER.ID
                            JOIN FILEUSERPERMISSIONS
                                ON FILEUSERPERMISSIONS.USERID=GROUPMEMBERSHIP.USERID
                            JOIN FILEGROUPPERMISSIONS
                                ON FILEGROUPPERMISSIONS.GROUPID=GROUPMEMBERSHIP.GROUPID
                        WHERE 
                            FILEUSERPERMISSIONS.FILEID=FILE.ID
                            AND FILEGROUPPERMISSIONS.FILEID=FILE.ID
                            AND FILEUSERPERMISSIONS.READ=FILE.READ
                            AND FILEGROUPPERMISSIONS.READ=FILE.READ
                            AND USER.ID=userID
                    )
                WHERE
                    FILE.READ=1
                    AND FILE.ID=fileID
            )
        THEN CAST(1 AS BIT)
        ELSE CAST(0 AS BIT)
        END
    ) AS hasRights

但是,如果您真的想重视您的功能。我建议使用表函数并只提供userid. 这样您就可以获得用户有权访问的所有文件。这看起来像这样:

SELECT
    ID
FROM
    FILE
WHERE EXISTS
    (
        SELECT
            NULL
        FROM
            USER
            JOIN GROUPMEMBERSHIP
                ON GROUPMEMBERSHIP.USERID=USER.ID
            JOIN FILEUSERPERMISSIONS
                ON FILEUSERPERMISSIONS.USERID=GROUPMEMBERSHIP.USERID
            JOIN FILEGROUPPERMISSIONS
                ON FILEGROUPPERMISSIONS.GROUPID=GROUPMEMBERSHIP.GROUPID
        WHERE 
            FILEUSERPERMISSIONS.FILEID=FILE.ID
            AND FILEGROUPPERMISSIONS.FILEID=FILE.ID
            AND FILEUSERPERMISSIONS.READ=FILE.READ
            AND FILEGROUPPERMISSIONS.READ=FILE.READ
            AND USER.ID=userID
    )
WHERE
    FILE.READ=1

顺便说一下。这个问题很好。这应该是一个如何提问的例子

于 2012-04-25T09:23:29.957 回答
0

为了完整起见,我还发布了我如何解决这个问题的解决方案。我最初的动机是创建一个函数来查看一个 linux 用户(即。user1)是否有权访问另一个 linux 用户(即。user2)的主文件夹(即。是否user1具有读取权限/home/user2)。然后,我将在使用该函数VIEW为每个 mysql 用户构造 a 时使用此user()函数(假设 mysql 用户名和 linux 用户名是一对一的)。感谢 Arion 的建议,我现在改为使用连接创建视图。

请注意,就本示例而言,主文件夹存储在FILE表中。

USER_VIEW 视图:

CREATE VIEW USER_VIEW
AS
SELECT 
   U.ID
FROM 
   USERS AS U
   LEFT JOIN FILES AS F
      ON U.ID = F.USER_ID
   LEFT JOIN FILE_USER_PERMISSIONS AS P
      ON F.ID = P.FILE_ID
   LEFT JOIN USERS AS S
      ON P.USER_ID = S.ID
WHERE
(
   U.USERNAME = SUBSTR( USER(), 1, POSITION( '@' IN USER() ) - 1 )
)
OR
(
   F.R = TRUE
)
OR
(
   U.HOME = F.PATH AND P.R = TRUE AND S.USERNAME = SUBSTR( USER(), 1, POSITION( '@' IN USER() ) - 1 )
)
UNION
SELECT 
   U.ID
FROM 
   USERS AS U
   LEFT JOIN FILES AS F
      ON U.ID = F.USER_ID
   LEFT JOIN FILE_GROUP_PERMISSIONS AS P
      ON F.ID = P.FILE_ID
   LEFT JOIN GROUP_MEMBERSHIP AS G
      ON P.GROUP_ID = G.ID
   LEFT JOIN USERS AS S
      ON G.USER_ID = S.ID
WHERE
(
   U.HOME = F.PATH AND P.R = TRUE AND S.USERNAME = SUBSTR( USER(), 1, POSITION( '@' IN USER() ) - 1 )
)

编辑:我相信而不是发出类似的命令

CREATE VIEW USER_VIEW
AS
SELECT 
   U.ID
FROM 
    ...

我只能做

CREATE VIEW USER_VIEW
AS
SELECT 
   U.*
FROM 
    ...

如果您想复制 10+ 列,这会派上用场

于 2012-05-04T19:29:42.963 回答