我在使用混合模式身份验证的 Microsoft SQL Server 2008 Express 实例中有一个名为 MyDB 的数据库。使用数据库 MyDB 的应用程序当前使用 Windows 身份验证连接,使用当前用户的 Windows 凭据。此登录是“公共”服务器角色的成员,并且在 MyDB 数据库中有一个用户映射到它。此数据库用户是 db_datareader 和 db_datawriter 数据库角色的成员。
我想要的是,当应用程序连接时,它有权在 MyDB 中读取和写入。但是当另一个应用程序使用相同的登录名连接时,它应该只被允许读取。
我的想法是我将创建一个登录触发器,它将检查连接字符串的应用程序名称部分,并据此决定是否应切换执行上下文。(作为记录,我知道依靠连接字符串的应用程序名称是不安全的,而且它很容易被规避。这里的目的不是保护数据库,而是帮助用户避免更改使用其他应用程序(例如 Microsoft Excel)连接时的数据)
我创建了一个名为“myapp_reader”的新登录名,映射到 MyDB 数据库中的用户,该用户是 db_datareader 的成员。
然后我尝试使用以下 TSQL 创建登录触发器:
CREATE TRIGGER CheckUser
ON ALL SERVER
AFTER LOGON AS
BEGIN
IF APP_NAME() <> 'My Application Name'
BEGIN
EXECUTE AS LOGIN = 'myapp_reader' WITH NO REVERT
END
END
但不幸的是,它不起作用。当我尝试连接时,出现以下错误:
由于触发器执行,登录“MyComputer\MyWindowsUsername”登录失败。
将数据库上下文更改为“主”。
将语言设置更改为 us_english。(Microsoft SQL Server,错误:17892)
当我查看错误日志时,它说:
错误:15590,严重性:16,状态:1
。只能在临时级别将“不还原”或“Cookie”选项与“执行为”语句一起使用。
错误:17892,严重性:20,状态:1
。由于触发器执行,登录“MyComputer\MyWindowsUsername”登录失败。[客户:xxx.xxx.xxx.xxx]
此错误是否意味着我无法永久更改登录触发器中的执行上下文?