6

我正在使用脚本来创建 Mysql 数据库和表。这些脚本包含如下授权部分:

GRANT SELECT ON my_database.* TO my_user@"%" IDENTIFIED BY 'my_password';
REVOKE ALL PRIVILEGES ON my_database.* FROM my_user@"%";
GRANT SELECT, UPDATE ON my_database.* TO my_user@"%" IDENTIFIED BY 'my_password';

最初,我只使用了第三行,但遇到了以下问题:每当我从用户中删除权限 Q 并重新运行该脚本时,该用户在数据库中仍然具有该权限。所以我在授权行之前添加了撤销行。

然后我遇到了以下问题:每当我在“全新”Mysql 安装上运行脚本时,撤销失败,因为用户还不存在。所以我在撤销之前添加了一个“虚拟”授权。

问题:有没有更好的方法来实现这一点?我的“真实”脚本包含大量用户和大量数据库并且难以阅读,因为我需要为要分配的每组权限设置三行代码。我只想使用一条线。

编辑(基于答案和评论的反馈):

我正在寻找最短的方式来表达类似

SET PRIVILEGES SELECT, UPDATE
ON my_database.*
TO my_user@"%"
IDENTIFIED BY 'my_password';

my_user 可能在哪里

  • 已经存在(但可能是新的)
  • 目前拥有扩展我希望他拥有的特权
  • 拥有其他数据库的权限,这些数据库必须不受影响
4

4 回答 4

5

如有必要,您可以使用过程创建新用户并授予数据库权限。我使用了准备好的语句和 GRANT 语句。MySQL 5.5 中的prepared statements 支持GRANT,如果您使用的是较低版本,则可以将GRANT 命令重写为INSERT INTO。

使用测试;

DELIMITER $$

CREATE PROCEDURE procedure_user(
  IN host_name VARCHAR(60),  IN user_name VARCHAR(60),
  IN db_name   VARCHAR(255),
  IN db_privs  VARCHAR(255))
BEGIN
  SELECT 1 INTO @exist FROM mysql.user WHERE user = user_name AND host = host_name;

  -- Create new user, generate command like this: CREATE USER 'user1'@'%';;
  IF @exist IS NULL THEN

    SET @sql = CONCAT('CREATE USER ''', user_name, '''@''', host_name, '''');
    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
  END IF;

  -- Generate command like this: GRANT INSERT, UPDATE ON database1.* TO 'user1'@'%';
  SET @sql = CONCAT('GRANT ', db_privs, ' ON ', db_name, '.* TO ''', user_name, '''@''', host_name, '''');
  PREPARE stmt FROM @sql;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;
END
$$

DELIMITER ;

使用示例:

-- First command will create new user user1@% and will grant SELECT, INSERT, UPDATE privileges to database1.
CALL procedure_user('%', 'user1', 'database1', 'SELECT, INSERT, UPDATE');

-- Second command just will grant SELECT, INSERT, UPDATE privileges to database2 to that user.
CALL procedure_user('%', 'user1', 'database2', 'SELECT, INSERT, UPDATE');
于 2011-10-13T16:30:14.210 回答
3

要确保用户存在而不授予任何权限:

GRANT USAGE ON *.* TO my_user@"%" IDENTIFIED BY 'my_password';

如果您真的想一步完成授权和撤销,您可能不得不直接使用内部权限存储表:

INSERT INTO `mysql`.`db` (
    `Host`, `Db`, `User`,
    `Select_priv`, `Insert_priv`, `Update_priv`, `Delete_priv`,
    `Create_priv`, `Drop_priv`, `Grant_priv`, `References_priv`, `Index_priv`, `Alter_priv`,
    `Create_tmp_table_priv`, `Lock_tables_priv`, `Create_view_priv`, `Show_view_priv`,
    `Create_routine_priv`, `Alter_routine_priv`, `Execute_priv`)
VALUES (
    'my_user', '%', 'my_database',
    'Y', 'N', 'Y', 'N',
    'N', 'N', 'N', 'N', 'N', 'N',
    'N', 'N', 'N', 'N',
    'N', 'N', 'N')
ON DUPLICATE KEY UPDATE
    `Select_priv` = 'Y', `Insert_priv` = 'N', `Update_priv` = 'Y', `Delete_priv` = 'N',
    `Create_priv` = 'N', `Drop_priv` = 'N', `Grant_priv` = 'N', `References_priv` = 'N', `Index_priv` = 'N', `Alter_priv` = 'N',
    `Create_tmp_table_priv` = 'N', `Lock_tables_priv` = 'N', `Create_view_priv` = 'N', `Show_view_priv` = 'N',
    `Create_routine_priv` = 'N', `Alter_routine_priv` = 'N', `Execute_priv` = 'N';

但是,它的可移植性较差,需要更多权限,并且在必要时不会创建用户帐户,因此使用三语句方法可能会更好。

为了帮助解决可读性问题,您可以创建某种带有帐户和权限的 CSV,从中生成 SQL 脚本。

于 2011-10-07T18:33:46.647 回答
3

很抱歉,实际上是评论的长答案,但我不明白。您的“第三行” GRANT 命令对我来说效果很好。这是应该起作用的两种情况。如果您可以发布一些重现错误的测试命令,那就太好了。至少我可以从中学习:)

案例#1,用户不存在:

mysql> SHOW GRANTS FOR my_user@"%";
ERROR 1141 (42000): There is no such grant defined for user 'my_user' on host '%'

好的,用户不存在。

mysql> create database my_database;
Query OK, 1 row affected (0.00 sec)

mysql> GRANT SELECT ON my_database.* TO my_user@"%" IDENTIFIED BY 'my_password';
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW GRANTS FOR my_user@"%";
+-----------------------------------------------------------------------+
| Grants for my_user@%                                                  |
+-----------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'my_user'@'%' IDENTIFIED BY PASSWORD '*CC...18' | 
| GRANT SELECT ON `my_database`.* TO 'my_user'@'%'                      | 
+-----------------------------------------------------------------------+
2 rows in set (0.00 sec)

好的,他有 SELECT 权限。

案例#2,用户存在并且也有other_database权利my_database

mysql> SHOW GRANTS FOR my_user@"%";
ERROR 1141 (42000): There is no such grant defined for user 'my_user' on host '%'

好的,用户不存在。

mysql> create database my_database;
Query OK, 1 row affected (0.00 sec)

mysql> create database other_database;
Query OK, 1 row affected (0.01 sec)

mysql> GRANT SELECT ON my_database.* TO my_user@"%" IDENTIFIED BY 'my_password';
Query OK, 0 rows affected (0.00 sec)

mysql> GRANT SELECT ON other_database.* TO my_user@"%" IDENTIFIED BY 'my_password';
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW GRANTS FOR my_user@"%";
+-----------------------------------------------------------------------+
| Grants for my_user@%                                                  |
+-----------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'my_user'@'%' IDENTIFIED BY PASSWORD '*CC...18' | 
| GRANT SELECT ON `other_database`.* TO 'my_user'@'%'                   | 
| GRANT SELECT ON `my_database`.* TO 'my_user'@'%'                      | 
+-----------------------------------------------------------------------+
3 rows in set (0.00 sec)

以上是测试夹具,现在我们向UPDATE用户授予新权限:

mysql> GRANT UPDATE ON my_database.* TO my_user@"%" IDENTIFIED BY 'my_password';
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW GRANTS FOR my_user@"%";
+-----------------------------------------------------------------------+
| Grants for my_user@%                                                  |
+-----------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'my_user'@'%' IDENTIFIED BY PASSWORD '*CC...18' | 
| GRANT SELECT ON `other_database`.* TO 'my_user'@'%'                   | 
| GRANT SELECT, UPDATE ON `my_database`.* TO 'my_user'@'%'              | 
+-----------------------------------------------------------------------+
3 rows in set (0.00 sec)

他的许可没有改变other_database,他也获得了新的UPDATE许可my_database和前者SELECT


根据评论,它应该只是UPDATE没有SELECT.

不幸的是,对于当前的 MySQL 版本,仅使用一个命令是不可能的。GRANT没有REMOVE EXISTING从句。

我认为最好的解决方案是@eswald GRANT USAGE ON ...,但它仍然是 3 个命令。另一种解决方案是

DELETE FROM mysql.db WHERE user = 'my_user' AND host ='%' AND db = 'my_database'

但它需要 aFLUSH PRIVILEGES所以它也是 3 个命令。

一种解决方法可能是一个 bash 脚本,它生成问题中的三个命令:

#!/bin/bash

function grant {
    USER=$1
    PASSWORD=$2
    DB=$3
    PERMISSIONS=$4

    echo "GRANT USAGE ON $DB TO $USER IDENTIFIED BY '$PASSWORD';"
    echo "REVOKE ALL PRIVILEGES ON $DB FROM $USER;"
    echo "GRANT $PERMISSIONS ON $DB TO $USER IDENTIFIED BY '$PASSWORD';"
}

grant "my_user@'%'" "my_password" "my_database.*" "SELECT, UPDATE"

它打印:

GRANT USAGE ON my_database.* TO my_user@'%' IDENTIFIED BY 'my_password';
REVOKE ALL PRIVILEGES ON my_database.* FROM my_user@'%';
GRANT SELECT, UPDATE ON my_database.* TO my_user@'%' IDENTIFIED BY 'my_password';

(我已将第一个更改GRANT SELECTUSAGE。)

于 2011-10-13T22:05:48.247 回答
0

我只是想知道,你跑了FLUSH PRIVILEGES吗?

于 2011-10-07T13:33:52.177 回答