如何编写好的Mysql授予脚本

时间:2011-10-05 12:34:50

标签: mysql grant

我正在使用脚本来创建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 个答案:

答案 0 :(得分:5)

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

USE测试;

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');

答案 1 :(得分: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脚本。

答案 2 :(得分:3)

很抱歉,实际上是一个评论的长答案,但我没有得到它。你的“第三线”GRANT命令对我很有用。这是两个应该起作用的案例。如果你能发布一些重现bug的测试命令,那就太好了。至少我可以从中学到:)

案例#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_databasemy_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'

但它需要一个FLUSH 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 SELECT更改为USAGE。)

答案 3 :(得分:0)

我只是想知道,你有没有运行FLUSH PRIVILEGES