2014-03-04 72 views
0

我們需要在主數據庫和從屬MySQL數據庫之間具有相同的用戶集合,但是要防止只讀用戶連接到主數據庫,並防止讀寫用戶連接到從數據庫。因此,我正在編寫登錄觸發器以防止某些用戶根據下表連接到MySql數據庫:有沒有辦法從登錄觸發器中徹底終止當前會話?

create table deny_login(user varchar(20),SLAVE_RUNNING varchar(3),deny varchar(1));

我使用「SLAVE_RUNNING」列來解釋如何區分觸發器內的主數據庫和從屬數據庫。

觸發器有效,但會話沒有正確終止。它斷開連接但嘗試重新連接等。是否有更簡潔的方式從觸發器中退出當前會話?

下面是表的內容以及觸發定義:

insert into deny_login values ('vlad','OFF', 'n'); 
insert into deny_login values ('joe','OFF','y'); 
insert into deny_login values ('[email protected]','OFF', 'n'); 
insert into deny_login values ('[email protected]','OFF','y'); 
insert into deny_login values ('[email protected]','ON','n'); 

create table test (user varchar(20), deny integer, connection integer); 

grant insert, update,delete on test to vlad; 
grant insert, update,delete on test to joe; 
grant insert, update,delete on test to bill; 
grant insert, update,delete on deny_login to vlad; 
grant insert, update,delete on deny_login to joe; 
grant insert, update,delete on deny_login to bill; 


DROP PROCEDURE IF EXISTS login_trigger; 

DELIMITER // 

CREATE PROCEDURE login_trigger() 
SQL SECURITY DEFINER 
BEGIN 
    declare denied integer; 
    select count(*) into denied from test.deny_login p, information_schema.global_status s where p.user=user() and user not 
    like '%root%' and s.variable_name='SLAVE_RUNNING' and s.variable_value=p.SLAVE_RUNNING and deny='y'; 
    insert into test values (user(),denied,connection_id()); 
commit; 

if denied = 1 then 
-- signal sqlstate '45000' set message_text = 'forbidden'; 
-- kill(connection_id()); 
call Fail('forbidden'); 
end if; 
END; 

// 
DELIMITER ; 


REVOKE EXECUTE ON PROCEDURE test.login_trigger FROM 'vlad'@'%'; 
GRANT EXECUTE ON PROCEDURE test.login_trigger TO 'vlad'@'%'; 
REVOKE EXECUTE ON PROCEDURE test.login_trigger FROM 'joe'@'%'; 
GRANT EXECUTE ON PROCEDURE test.login_trigger TO 'joe'@'%'; 
REVOKE EXECUTE ON PROCEDURE test.login_trigger FROM 'bill'@'%'; 
GRANT EXECUTE ON PROCEDURE test.login_trigger TO 'bill'@'%'; 

SET GLOBAL init_connect=""; 
SET GLOBAL init_connect="CALL test.login_trigger()"; 

回答

0

在奴隸,SET GLOBAL READ_ONLY = 1;。然後,具有寫權限的用戶將無法寫入從機......任何嘗試更改數據的操作都將遇到一個錯誤,說明從本質上講,「從機正在以只讀模式運行」,寫操作將會否認。

具有SUPER權限的用戶將保留寫入權限(但它們無論如何都不受init_connect的限制),並且複製線程不會受到影響。

對於不需要訪問主服務器的用戶,從主服務器中刪除他們的帳戶並直接將它們添加到從服務器。只要您不會將相同的用戶添加回主服務器,而不會先將其從服務器中刪除,那麼這不會造成問題。

如果客戶試圖自行重新連接,沒有更好的方法來做你正在嘗試的東西。你正在做一個乾淨的斷開連接。我可以想到的唯一替代方法是嘗試,而不是終止連接,可能會在程序中放置一個ROLLBACK RELEASE;,這也會導致客戶端連接中斷,儘管我懷疑客戶端仍會嘗試重新連接,如果斷開連接是客戶意想不到的。

https://dev.mysql.com/doc/refman/5.6/en/server-system-variables.html#sysvar_read_only

順便說一下,在當前實現中,一個簡單的方法來主機和從機之間進行區分。將檢查@@SERVER_ID@@HOSTNAME變量的值。

相關問題