对于应用程序来说,最小的权限通常就是就是给予读权限,写权限和执行存储过程权限。由于为了防止SQL注入导致的数据库信息泄漏,则还需要考虑拒绝帐号的查看定义权限,但值得注意的是,如果拒绝了查看定义的权限,则Bulk Insert会失败。完整的权限定义如下:
ALTER ROLE [db_datareader] ADD MEMBER 用户名 ALTER ROLE [db_datawriter] ADD MEMBER 用户名 grant execute to 用户名 deny view definition to 用户名
在SQL Server中,实例级别的是登录名,而数据库级别的才是用户名,登录名在创建完成后可映射到具体的库。因此我写了一个完整的脚本,同时创建登录名,用户,以及赋予对应的权限,脚本如下:
--创建用户的存储过程, --示例EXEC sp_CreateUser &#39;UserName&#39;,&#39;rw&#39;,&#39;DatabaseName&#39; --EXEC sp_CreateUser &#39;tesefx&#39;,&#39;r&#39;,&#39;Test&#39;,&#39;0xE39CA97EBE03BB4CA5FF78E50374EEBB&#39; CREATE PROC sp_CreateUser @loginName VARCHAR(50) , @IsWrite VarCHAR(3) , @DatabaseName VARCHAR(50), @Sid VARCHAR(100) =&#39;1&#39; AS PRINT(&#39;示例:EXEC sp_CreateUser &#39;&#39;UserName&#39;&#39;,&#39;&#39;rw&#39;&#39;,&#39;&#39;DatabaseName&#39;&#39;&#39;) PRINT(&#39;示例:EXEC sp_CreateUser &#39;&#39;UserName&#39;&#39;,&#39;&#39;rwv&#39;&#39;,&#39;&#39;DatabaseName&#39;&#39;,&#39;&#39;0xE39CA97EBE03BB4CA5FF78E50374EEBB&#39;&#39;&#39;) PRINT(&#39;r为只读权限,rw为读写权限,rwv为读写加View Definition权限&#39;) IF EXISTS ( SELECT name FROM sys.syslogins WHERE name = @loginName ) BEGIN PRINT N&#39;登录名已存在,跳过创建登录名步骤&#39; END ELSE BEGIN DECLARE @CreateLogin NVARCHAR(1000) DECLARE @pwd VARCHAR(50) PRINT @Sid SET @pwd=NEWID() IF(@sid=&#39;1&#39;) BEGIN SET @CreateLogin = &#39;CREATE LOGIN [&#39; + @loginName + &#39;] WITH PASSWORD=N&#39;&#39;&#39; + @Pwd + &#39;&#39;&#39;, DEFAULT_DATABASE=[master], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF;&#39; PRINT N&#39;登录名已创建,密码为:&#39;+@pwd END ELSE BEGIN SET @CreateLogin = &#39;CREATE LOGIN [&#39; + @loginName + &#39;] WITH PASSWORD=N&#39;&#39;&#39; + @Pwd + &#39;&#39;&#39;, DEFAULT_DATABASE=[master], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF,sid=&#39;+@Sid+&#39;;&#39; PRINT N&#39;已经使用SID创建登录名:&#39;+@loginName END EXEC (@CreateLogin) --DECLARE @sidtemp NVARCHAR(50) --SELECT @sidtemp=sid FROM sys.server_principals WHERE name=@loginName --PRINT(N&#39;登录名为:&#39;+@loginName+N&#39; SID为: 0x&#39;+CONVERT(VARCHAR(50), @sidtemp, 2) ) END DECLARE @DynamicSQL NVARCHAR(1000) --切换数据库上下文 SET @DynamicSQL = N&#39;Use [&#39; + @DatabaseName + &#39;]; &#39; + &#39;IF EXISTS(SELECT name FROM sys.database_principals WHERE name=&#39;&#39;&#39;+@loginName+&#39;&#39;&#39;) Begin Print(&#39;&#39;用户名已存在,跳过创建用户名的步骤&#39;&#39;) end else begin CREATE USER [&#39; + @loginName + &#39;] FOR LOGIN &#39; + @loginName + &#39; end;IF (&#39;&#39;&#39; + @IsWrite + &#39;&#39;&#39;=&#39;&#39;rw&#39;&#39; or &#39;&#39;&#39; + @IsWrite + &#39;&#39;&#39;=&#39;&#39;rwv&#39;&#39;) BEGIN ALTER ROLE [db_datareader] ADD MEMBER &#39; + @loginName + &#39;;ALTER ROLE [db_datawriter] ADD MEMBER &#39; + @loginName + &#39;; END ELSE BEGIN ALTER ROLE [db_datareader] ADD MEMBER &#39; + @loginName + &#39;; ALTER ROLE db_datawriter DROP MEMBER &#39; + @loginName + &#39; ;End;grant execute to &#39; + @loginName + &#39;; if(&#39;&#39;&#39;+@IsWrite+&#39;&#39;&#39;<>&#39;&#39;rwv&#39;&#39;) begin deny view definition to &#39; + @loginName + &#39;; end else begin grant view definition to &#39; + @loginName + &#39;; end&#39; EXEC (@DynamicSQL)
该存储过程用于创建应用程序连接SQL Server所需的登录名,用户以及对应权限,当用户或登录名存在时还会跳过该步骤,使用该存储过程的示例如:
EXEC sp_CreateUser &#39;UserName&#39;,&#39;rw&#39;,&#39;DatabaseNam&#39; EXEC sp_CreateUser &#39;tesefx&#39;,&#39;r&#39;,&#39;Test&#39;,&#39;0xE39CA97EBE03BB4CA5FF78E50374EEBB&#39;
上述执行的第一行是创建一个标准的帐号,账户名UserName,赋予对DatabaseNam的库的读写权限,并返回生成的GUID密码。第二个存储过程是使用第四个参数sid创建登录名,由于在AlwaysOn或镜像的环境中,两端登录名需要有相同的SID,因此提供了在该情况下使用SID创建登录名的办法。