现在的位置: 首页 > 综合 > 正文

关于修改mysql账号信息导致存储过程无法访问的问题

2018年01月21日 ⁄ 综合 ⁄ 共 5238字 ⁄ 字号 评论关闭

因为某某离职,公司要求将他所有负责的业务系统的mysql账号都进行修改(直接删除,然后创建新账号),不过删除后却发现很多视图和存储过程访问不了。

因为该问题是mysql运维中比较典型的问题所以今天抽空记录一下:

情况是这么个情况:

之前使用的用户:dmpapadmin@'124.205.200.130' 然后领导要求drop 。

现在新建用户:dmpapadmin@'218.247.217.66' 然后授权grant all db_name.* to dmpapadmin@218.247.217.66'

然后使用新用户调用存储过程,报错如下:

 [Err] 1449 - The user specified as a definer ('dmpapadmin'@'124.205.200.130') does not exist

很明显了报错说 ,嘿:对不起找不到账号'dmpapadmin'@'124.205.200.130'

很自然想到proc 里出了问题,好查看:

select * from proc limit 1 \G
*************************** 1. row ***************************
                  db: dsmcenter
                name: bak_aaaaaa
                type: PROCEDURE
       specific_name: bak_aaaaaa
            language: SQL
     sql_data_access: CONTAINS_SQL
    is_deterministic: NO
       security_type: DEFINER
          param_list: 
             returns: 

省略存储过程body信息

definer: dmpapadmin@124.205.200.130
             created: 2014-03-03 17:59:22
            modified: 2014-02-13 17:31:21
            sql_mode: STRICT_TRANS_TABLES
             comment: 
character_set_client: utf8
collation_connection: utf8_general_ci
        db_collation: utf8_bin

看到了吧,存储过程里definer 依然是原来的旧账号,执行存储过程的时候存mysql会去找dmpapadmin@124.205.200.130

如果找不到自然就报错了。

这里需要了解一点基础知识,即存储程序(或说视图,函数,存储过程)他们都有一个SQL SECURITY 属性该属性有连个选择{ DEFINER | INVOKER } 

默认情况是definer 即定义者默认情况下deiner的值就是创建存储程序的当前用户,当调其他用户调用存储过程的时候

存储过程回去检查definer里的用户是否存在并且调用用户是否有权限执行(如果用户有super权限那直接可以调用存储程序

如果具有存储过程所在数据库的all on db_name.*权限亦可调用存储过程)。


那么definer,invoke是如何影响存储过程的调用呢? 请看如下实验:


1,创建安全类型为 invoker的存储过程,definer 为 root@localhost

drop procedure if exists t_p; \d $$ create DEFINER='root'@'localhost' procedure t_p() SQLSECURITY INVOKER begin select 1; end;$$  \d ;   
*********** 3. row ***************************
                  Db: itop1011
                Name: t_p
                Type: PROCEDURE
             Definer: root@localhost
            Modified: 2014-03-04 15:01:39
             Created: 2014-03-04 15:01:39
       Security_type: INVOKER
             Comment: 
character_set_client: utf8
collation_connection: utf8_general_ci
  Database Collation: utf8_bin

然后创建一个新的用户:

grant all on itop1011.* to test@'localhost';

然后使用test用户调用call t_p(); 

call t_p();
+---+
| 1 |
+---+
| 1 |
+---+

2,创建安全类型为definer的存储过程 definer 为 root@localhost

drop procedure if exists t_p_d; \d $$ create DEFINER='root'@'localhost' procedure t_p_d()SQL SECURITY definer begin select 1; end;$$ \d ;

************ 5. row ***************************
                  Db: itop1011
                Name: t_p_d
                Type: PROCEDURE
             Definer: root@localhost
            Modified: 2014-03-04 15:05:38
             Created: 2014-03-04 15:05:38
       Security_type: DEFINER
             Comment: 
character_set_client: utf8
collation_connection: utf8_general_ci
  Database Collation: utf8_bin

同样test用户登录调用存储过程t_p_d()

call t_p_d();
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.00 sec)

上述结果说明:只要拥有执行存储过程的权限(all包括了Execute权限)definer即使是具有super权限的root用户也 并不影响任何合法调用者

3,创建存储安全类型为invoker类型的存储过程,definer 为 test@localhost

drop procedure if exists t_p; \d $$ create DEFINER='test'@'localhost'procedure t_p() SQLSECURITY INVOKER begin select 1; end;$$ \d ;      

*********** 8. row ***************************
                  Db: itop1011
                Name: t_p
                Type: PROCEDURE
             Definer: test@localhost
            Modified: 2014-03-04 15:16:59
             Created: 2014-03-04 15:16:59
       Security_type: INVOKER
             Comment: 
character_set_client: utf8
collation_connection: utf8_general_ci
  Database Collation: utf8_bin

创建另一个普通用户test1

grant all on itop1011.* to test1@'localhost';

然后调用call t_p();
+---+
| 1 |
+---+
| 1 |
+---+

4,创建安全类型为definer的存储过程,definer 为test@localhost

drop procedure if exists t_p_d; \d $$ create DEFINER='test'@'localhost' procedure t_p_d()SQL SECURITY definer begin select 1; end;$$ \d ;

*************************** 9. row ***************************
                  Db: itop1011
                Name: t_p_d
                Type: PROCEDURE
             Definer: test@localhost
            Modified: 2014-03-04 15:22:16
             Created: 2014-03-04 15:22:16
       Security_type: DEFINER
             Comment: 
character_set_client: utf8
collation_connection: utf8_general_ci
  Database Collation: utf8_bin

然后使用普通用户test1调用call t_p_d();
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.00 sec)

上述结果说明:只要存储过程调用者test1具有存储过程的调用权限,无论存储过程的definer是谁,SQL SECURITY是definer还是invoker都无所谓。

5,删除 SQL SECURITYdefiner的存储过程t_p_d的用户test@localhost
然后使用test1调用存储过程

call t_p_d();
ERROR 1449 (HY000): The user specified as a definer ('test'@'localhost') does not exist

报错信息:调用存储过程的时候回去检查definer用户是否存在,不存在则报错。


6,删除 SQL SECURITYinvoker
的存储过程t_p_d的用户test@localhost 然后使用test1调用存储过程

 call t_p();
+---+
| 1 |
+---+
| 1 |
+---+
正常调用,一切都那么的ok。

7,在(5)的基础上创建用户grant all on itop1011.* to test@'%'; 然后使用test1调用

call t_p_d();             
+---+
| 1 |
+---+
| 1 |
+---+

8,在(5)的基础上创建用户grant all on itop1011.* to test@'192.156.11.23'; 然后使用test1调用

call t_p_d();
ERROR 1449 (HY000): The user specified as a definer ('test'@'localhost') does not exist

(5),(6),(7),(8) 说明 当security_type为definer的时候 当存储过程被调用的时候mysql会去检查 definer用户如果不存在就报错,上面定义了一个test@'%'的用户后又可以调用是因为%包括了localhost(这里需要提醒一下,如果你通过普通用户定义了很多存储过程或试图或函数,那么当你打算修改该用户的时候你就要注意了,需要同时修改他们的definer为新的用户,否则调用的时候则会报错)而当security_type
为调用者的时候则没影响。
因此这里建议创建存储程序的时候SQL SECURITY定义为invoker 。

结论:

      如果你的数据库里打算大量使用存储程序(func,proc)或试图,那么你最好让他们的SQL SECURITY都定义为invoke,这样可以避免未来修改账号而导致

存储程序和试图不可访问。同时在mysqldump的时候会报错如:mysqldump: Got error: 1449: The user specified as a definer ('xxx'@'122.215.201.110') does not exist when using LOCK TABLES


ps: 另外要提示的一个问题是我们可以通过修改mysql.proc (proc里包含了function,这里注意func里并不会存储function的信息) 来修改存储

过程和函数的SQL SECURITY的属性。不过如果是视图那么对不起你只能先导出然后修改definer后再导入了具体:

select concat('create OR REPLACE SQLSECURITY INVOKER VIEW
',TABLE_NAME,' as ',VIEW_DEFINITION,';') AS def from information_schema.views \G 然后拷贝出来重建即可。


参考:http://dev.mysql.com/doc/refman/5.5/en/create-procedure.html

           http://dev.mysql.com/doc/refman/5.5/en/create-view.html

抱歉!评论已关闭.