6

質問:

私はmySQLにかなり慣れていないので、どこから始めればよいかさえわかりません。多くのテーブルに分散された値に基づいて true または false を返す単純な関数を作成する方法を知りたいです。

詳細:

これが私のテーブルの関連部分です(すべてのエンジンは です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 に対する読み取り権限を持つグループに属しているかどうかを確認します。

最初のものはかなり些細なこと3つの中で最も些細なこと。2番目のものは私を困惑させました。3 つ目は、私にとって概念的な障壁です。これらすべてに加えて、明らかに、ユーザーやファイルが存在するかどうかを確認する必要があります。

私は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

完全を期すために、この問題をどのように解決したかについての解決策も投稿しています。user1私の最初の動機は、ある Linux ユーザー (つまり) が別の Linux ユーザー (つまりuser2) のホーム フォルダーにアクセスできるかどうか (つまりuser1、 に対する読み取り権限があるかどうか)を確認する関数を作成することでした/home/user2VIEW次に、関数を使用して各 mysql ユーザーを作成するときに、この関数を使用しuser()ます (mysql ユーザー名と Linux ユーザー名が 1 対 1 であると仮定します)。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 に答える