關於什麼是用戶權限,最簡單的定義可能是,“用戶能做什麼和不能做什麼。”在這裡,簡單的定義就相當不錯了。
用戶的權限分為3類:
l 登錄的權限;
l 訪問特定數據庫的權限;
l 在數據庫中具體的對象上執行特定操作的權限。
既然我們已經看過了創建登錄賬戶,這裡將把重點放在登錄賬戶能夠擁有的特定權限上。
22.3.1 授予訪問特定數據庫的權限 如果想要一個用戶可以訪問數據庫,你需要做的第一件事情是授予用戶訪問那個數據庫的權限。可以在Management Studio中,通過把用戶加入到服務器的數據庫結點的用戶成員中來實現。如果要用T-SQL來添加用戶,需要使用CREATE USER或遺留的存儲過程sp_grantdbaccess。
注意,當你在數據庫中CREATE一個用戶時,實際上,那些許可權限被存儲在數據庫中,並映射到那個用戶的服務器標識符上。當還原數據庫時,可能不得不在還原數據庫的地方,重新把用戶權限映射到服務器標識符。
1.CREATE USER CREATE USER命令把新用戶添加到數據庫中。用戶可以源自現有的登錄名、證書或非對稱密鑰,用戶也可以是只能在當前數據庫中的本地用戶。其語法如下:
CREATE USER <用戶名>
[ { { FOR | FROM }
{
LOGIN <登錄名>
| CERTIFICATE <證書名>
| ASYMMETRIC KEY <密鑰名>
}
| WITHOUT LOGIN ]
[ WITH DEFAULT_SCHEMA = <模式名> ]
對於這些元素,我們概略看一下其中一些元素的含義是什麼:
選 項
說 明
LOGIN
想要授予訪問當前數據庫的權限的登錄名
CERTIFICATE 與用戶關聯的證書的邏輯名稱。注意,必須已經使用CREATE CERTIFICATE命令創建了證書
ASYMMETRIC KEY
與用戶關聯的非對稱密鑰的邏輯名稱。注意,必須已經使用CREATE ASYMMETRIC KEY命令創建了密鑰
WITHOUT LOGIN
創建只能在當前數據庫中活動的用戶。可以用它來建立特定的安全上下文,但是,該用戶不能映射到當前數據庫之外的登錄名,也不能訪問任何其他的數據庫
WITH DEFAULT_SCHEMA
設立不是默認的“dbo”的模式,以作為當前用戶的默認模式
2.sp_grantdbaccess 這是遺留的方法,用來授予登錄名到特定數據庫的訪問權限。其語法如下:
sp_grantdbaccess [@loginame =] <'登錄名'>[, [@name_in_db =] <'數據庫中的別名'>
注意,授予的是當前數據庫的訪問權限——即是說,你 必須確保想要用戶能夠訪問的數據庫是發出該命令時的當前數據庫。登錄名是用來登錄到SQL Server中的實際的登錄ID。參數name_in_db允許給該用戶另外的識別名稱。這個別名只適用於此處的數據庫——其他所有的數據庫仍將使用該登 錄ID的默認名稱,或者使用在授予用戶那個數據庫的訪問權限時所定義的別名。定義別名將影響身份識別函數,如USER_NAME()。系統級別的函數(如 SYSTEM_USER)將返回基礎的登錄ID。
22.3.2 授予數據庫中對象的權限 好吧,用戶擁有了登錄名,並且,能夠訪問你想要他或她可以訪問的數據庫,那麼,是否現在就萬事大吉了呢?如果事情真有那麼簡單就好了!現在當然還沒有一切就緒。
在用戶能夠訪問什麼的問題上,SQL Server給了我們級別相當精細的控制。多數時候,一些信息是希望用戶能夠訪問到的,但是,數據庫中也有另一些信息是不希望用戶訪問的。例如,你可能想 要客戶服務人員能夠查看和維護訂單信息,但是可能不希望他們亂看工資信息。或許,反之亦然——你需要人力資源人員能夠編輯雇員記錄,但是,或許不想要他們 在交易上給某人很大的折扣。
SQL Server允許你給SQL Server中一些不同的對象指派一組不同的權限。能夠為其指派權限的對象包括表、視圖和存儲過程。觸發器隱含具有創建它們的人的權限。
對象上的用戶權限分為6種不同的類型。
用戶權限
說 明
SELECT 允許用戶“看到”數據。如果用戶擁有該權限,則用戶能夠在其被授予權限的表或視圖上運行SELECT語句
INSERT 允許用戶創建新的數據。具有這種權限的用戶能夠運行INSERT語句。注意,與許多系統不同,具有INSERT能力並不一定意味著擁有SELECT權限
UPDATE 允許用戶修改已有的數據。具有這種權限的用戶能夠運行UPDATE語句。類似於INSERT語句,具有UPDATE能力並不一定意味著擁有SELECT權限。
DELETE 允許用戶刪除數據。具有這種權限的用戶能夠運行DELETE語句。同樣,具有DELETE能力不一定意味著擁有
SELECT權限 REFERENCES
在要插入行的表中有引用另一個表的外鍵約束,而用戶在那個表上沒有SELECT權限,REFERENCES權限允許用戶插入行
EXECUTE 允許用戶EXECUTE指定的存儲過程
在你正在把權限指定到其上的特定的表、視圖或存儲過程中,可以在需要時混合搭配這些權限。
可以在Management Studio中指派這些權限,你只需導航到服務器的“安全性”結點的“登錄名”選項上。在用戶上右擊,並選擇“屬性”。根據你是在數據庫中還是在安全性結 點中,打開的對話框將有所不同,但是,無論哪一種情況,都能夠得到設置權限的選項。使用T-SQL指派權限會使用三個命令,了解這三個命令是有益的,即使 你只准備通過Management Studio來指派權限(術語是相同的)。
1.GRANT GRANT把對象上指定的訪問權限給予指定的用戶或角色,對象是GRANT語句的主體。
GRANT語句的語法如下所示:
GRANT
ALL [PRIVILEGES] | <權限>[,...n]
ON
<表名或視圖名>[(<列名>[,...n])]
|<存儲過程或擴展存儲過程名>
TO <登錄ID或角色名>[,...n]
[WITH GRANT OPTION]
[AS <角色名>]
ALL關鍵字表示你想要授予的是適用於那個對象類型的所有權限(EXECUTE絕不適用於表)。如果不使用ALL關鍵字,則需要提供一個或多個具體的權限,這些具體的權限是針對那個對象想要授予的。
PRIVILEGES是一個新的關鍵字,它除了提供ANSI-92兼容性外沒有實際的功能。
ON關鍵字用作一個占位符,以說明接下來的是想要授予其權限的對象。注意,如果你是在表上授予權限,可以通過明確說明受影響的列的列表來指定下至列級的權限——如果不提供具體的列,則認為將影響所有的列。
在對列級權限的看法 上,微軟似乎做的是些表面的事情。能夠說一個用戶可以在特定的表上進行SELECT,但僅限於在該表中特定的列上進行SELECT,這似乎很酷,然而,在 列級權限的使用中以及微軟為實現列級權限所做的工作中,確實讓安全性處理太過錯綜復雜了。鑒於此,近來關於該主題的文獻,以及我從內部人士那裡得到的消 息,似乎都表明微軟想要丟棄列級安全性了。在使用上他們建議——如果需要限制用戶只能看到特定的列,請改為考慮使用視圖。
TO語句所做的事情正如你期望的那樣——它指定想要把該訪問權限授予誰。被授予權限的可以是登錄ID或角色名。
WITH GRANT OPTION允許你向其授予訪問權限的用戶也能向其他用戶授予訪問權限。
由於使用該選項 後,要了解誰獲得了訪問什麼的權限,將很快變得十分痛苦,因此,我建議避免使用該選項。當然,你總是可以進入到Management Studio中來查看對象上的權限,但那是被動反應的方式而非積極主動的方式——你是在查找當前訪問級別上哪裡出錯了,而不是事先停止不希望發生的訪問。
最後,但並非最不重要的,是AS關鍵字。該關鍵字處理的是一個登錄名屬於多個角色的問題。
接下來,我們來看一、兩個例子。後面將看到,我們已 經創建的TestAccount賬戶,基於其是Public角色(所有的數據庫用戶都屬於的東西,並且,無法從中移除)中的成員而擁有了一些訪問權限。然 而,尚有大量的項目是TestAccount不具有訪問權限的(由於Public是TestAccount唯一屬於的角色,因此,Public也不具有那 些權限)。
先從以TestAccount用戶登錄開始。然後在Region表上嘗試一個SELECT語句:
很快,你將收到來自SQL Server的消息,告知:你正在嘗試去到你所不應該訪問的地方。
單獨以sa登錄——如果你願意,也可以在同一個查詢編輯器實例中,通過選擇菜單“文件”→“連接”,來完成這件事情。然後,為新的連接選擇“SQL Server身份驗證”,並用正確的密碼以sa身份登錄。現在,執行GRANT語句:
接著,切換回TestAccount連接(要記住,以什麼用戶進行連接的信息顯示在連接窗口的標題欄中),然後,再嘗試執行SELECT語句:這一次,得到了好得多的結果:
我們繼續嘗試另外的語句。這一次,我們在EmployeeTerritories表上運行相同的測試和命令:
該語句執行失敗——這同樣是由於你不具備相應的權限所致,因此,授予用戶該表上的權限:
然後,再次運行SELECT語句,一切進展順利:
不過,若要再添加一點變化,嘗試在這個表中執行INSERT:
SQL Server立即會讓我們走開——我們不具備必要的權限,因此,授予用戶相應的權限(使用sa連接):
現在,再次運行INSERT語句:
一切進展順利。
2.DENY DENY明確阻止用戶獲得目標對象上指定的訪問 權限。DENY的關鍵所在是,它將覆蓋任何GRANT語句。由於用戶可以屬於多個角色(馬上將對此進行討論),因此,一個用戶可能屬於被授予了訪問權限的 角色,但同時又受DENY的影響。如果用戶個人的權限和基於角色成員身份所獲得的權限混合在一起,DENY和GRANT同時存在於其中,那麼DENY總是 優先的。簡言之,如果用戶或用戶所屬的任何角色在權限問題上有DENY出現,則用戶將不能使用在那個對象上的訪問權限。
其語法很復雜繁多,看上去與GRANT語句一樣:
DENY
ALL [PRIVILEGES]|<權限>[,...n]
ON
<表名或視圖名>[(列名[,...n])]
|<存儲過程或擴展存儲過程名>
TO <登錄ID或角色名>[,...n]
[CASCADE]
同樣,ALL關鍵字表明,想要拒絕授予該對象類型上所有可用的權限(EXECUTE絕不適用於表)。如果不使用ALL關鍵字,則需要提供一個或多個具體的權限,這些具體的權限是針對想要拒絕授予權限的對象的。
PRIVILEGES依然是新關鍵字,並且,除了提供ANSI-92兼容性外沒有任何實際的功能。
ON關鍵字用作一個占位符,以說明接下來的是想要拒絕授予其權限的對象。
到此為止,所有的事情都與GRANT語句幾乎一樣。 CASCADE關鍵字與GRANT語句中的WITH GRANT OPTION相對應。CASCADE告訴SQL Server,如果用戶在WITH GRANT OPTION規則下授予了其他人訪問權限,則對於所有這些人,也拒絕他們的訪問。
為了在DENY上運行一個例子,我們使用TestAccount登錄名嘗試執行一個簡單的SELECT語句:
運行該語句後,將返回大約9條記錄。在我們不曾授予TestAccount該權限時,它是如何獲得訪問權限的呢?原因是,TestAccount屬於Public,而Public被授予了Employees上的訪問權限。
假如我們不希望TestAccount能夠訪問Employees。無論什麼原因,TestAccount是一個例外,並且我們不希望該用戶查看那些數據——我們只需發出DENY語句(記住要使用sa登錄名來運行DENY):
當再次用TestAccount登錄名運行SELECT語句時,將得到一個錯誤——你不再能夠訪問。此外還要注意,由於我們使用了ALL關鍵字,因此,也拒絕將Public所擁有的INSERT、DELETE和UPDATE訪問權限授予TestAccount。
注意,DENY是SQL Server 7.0中新增的語句。在6.5版本中有拒絕授予權限的概念,但是,其實現方式是不同的。在6.5版中,不是使用DENY,而是發出兩次REVOKE語句。新的DENY關鍵字讓事情更加清晰明了。
3.REVOKE REVOKE將消除以前發出的GRANT或DENY語句的影響。可以把該語句想成是有針對性的“撤銷”語句。
REVOKE的語法混合了GRANT和DENY語句:
REVOKE [GRANT OPTION FOR]
ALL [PRIVILEGES] | <權限>[,...n]
ON
<表名或視圖名>[(列名 [,...n])]
|<存儲過程或擴展存儲過程名>
TO | FROM <登錄ID或角色名>[,...n]
[CASCADE]
[AS <角色名>]
實際上,這裡要做的說明與對GRANT和DENY語句的說明相同——然而,我將在這裡再次講述,以免你為了快速查找有關REVOKE的說明而向前翻閱本書。
同樣,ALL關鍵字表明,想要撤銷在該對象類型上所有可用的權限。如果不使用ALL關鍵字,則需要提供一個或多個具體的權限,這些具體的權限是針對那個對象想要撤銷的權限。
PRIVILEGES除了提供ANSI-92兼容性外,依然沒有任何實際的作用。
ON關鍵字用作一個占位符,以說明接下來的是想要撤銷其權限的對象。
CASCADE關鍵字與GRANT語句中的WITH GRANT OPTION相對應。CASCADE告訴SQL Server,如果用戶在WITH GRANT OPTION規則下授予了其他人訪問權限,則對於所有這些被授予權限的人,也將撤銷他們的訪問權限。
同樣,AS關鍵字只是用來說明想要基於哪個角色發出這一命令。
我們使用sa連接,撤銷授予的到NorthwindSecure中的Region表的訪問權限。
執行完該語句後,TestAccount將不能再在Region表上運行SELECT語句。
為了撤銷DENY,我們同樣也發出一個REVOKE語句。這一次,將重新獲得到Employees表的訪問權限:
現在,我們已經了解所有這些命令是如何針對單個用戶來控制訪問權限的,接下來,看這樣一種方法,該方法通過分組管理來極大簡化對這些權限的管理。
22.3.3 用戶權限和語句級別的許可 用戶許可權限並不僅僅局限於數據庫中的對象上——它們也能擴展到某些其他的語句,這些語句不直接與任何特定的對象束縛在一起。SQL Server允許你對運行幾種不同的語句的許可權限進行控制,這些語句包括:
l CREATE DATABASE;
l CREATE DEFAULT;
l CREATE PROCEDURE;
l CREATE RULE;
l CREATE TABLE;
l CREATE VIEW;
l BACKUP DATABASE;
l BACKUP LOG。
到現在為止,除了兩個備份命令外,其他所有的這些命令我們都已經在操作中見過了。(備份命令要做什麼是不言自明的,因此,眼下不准備在這上面花費時間,我們將在第24章中討論它們——只需記住,它們是你能夠在語句級別進行控制的東西。)
那麼,我們如何指派這些許可權限呢?實際上,現在你 已經見過GRANT、REVOKE和DENY針對對象的運作,那麼,在語句級別的許可權限上你也已經有了相當的了解。從語法構成上說,它們與對象級別的許 可權限基本相同,除了它們更加簡單(你不必填入那樣多的東西)。其語法如下:
GRANT <ALL | 語句[,...n]> TO <登錄 ID>[,...n]
很簡單吧?接下來,通過驗證我們的測試用戶尚沒有權力執行CREATE,以進行一次快速的試驗。確保以TestAccount登錄,然後,運行下面的命令(在下面的語句中,不要忘記把ARISTOTLE轉換到你的域名):
我們運行上面的命令是完全行不通的:
現在,使用sa賬戶(或者其他具有NorthwindSecure的dbo權力的賬戶)登錄到SQL Server中。然後,運行命令以授予許可權限:
你會得到命令成功執行的確認消息。然後,再次嘗試運行CREATE語句(記住使用TestAccount登錄):
這一次一切順利。
在對象級別的許可權限上,DENY和REVOKE也以同樣的方式工作。