Sql server 在登录触发器内切换执行上下文

Sql server 在登录触发器内切换执行上下文,sql-server,permissions,triggers,authentication,execute-as,Sql Server,Permissions,Triggers,Authentication,Execute As,我在一个使用混合模式身份验证的Microsoft SQL Server 2008 Express实例中有一个名为MyDB的数据库。使用数据库MyDB的应用程序当前使用Windows身份验证,使用当前用户的Windows凭据进行连接。此登录名是“public”服务器角色的成员,并且在MyDB数据库中映射了一个用户。此数据库用户是db_datareader和db_datawriter数据库角色的成员 我想要的是,当应用程序连接时,它拥有在MyDB中读写的权限。但是,当另一个应用程序使用相同的登录连接

我在一个使用混合模式身份验证的Microsoft SQL Server 2008 Express实例中有一个名为MyDB的数据库。使用数据库MyDB的应用程序当前使用Windows身份验证,使用当前用户的Windows凭据进行连接。此登录名是“public”服务器角色的成员,并且在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
创建触发器CheckUser
在所有服务器上
登录后作为
开始
如果应用程序名()为“我的应用程序名”
开始
以登录名执行='myapp_reader',不还原
结束
结束
但不幸的是,它不起作用。当我尝试连接时,出现以下错误:

由于触发执行,登录“MyComputer\MyWindowsUsername”失败。
已将数据库上下文更改为“master”。
将语言设置更改为美国英语。(Microsoft SQL Server,错误:17892)

当我查看错误日志时,它会说:

错误:15590,严重性:16,状态:1。
只能在临时级别将“No Revert”或“Cookie”选项与“Execute As”语句一起使用。
错误:17892,严重性:20,状态:1。
由于触发器执行,登录“MyComputer\MyWindowsUsername”失败。[客户:xxx.xxx.xxx.xxx]


此错误是否意味着我无法永久更改登录触发器中的执行上下文?

我认为不可能更改整个会话的执行上下文。您可以为数据库中的每个表/视图创建一个用于插入、更新和删除的DML触发器,该表/视图对某个app_name()进行回滚。您可以编写一个过程来自动创建所有这些触发器


或者,如果您可以选择让Excel等应用程序通过链接服务器连接,那么此时您可以更改执行上下文。并创建一个登录触发器,如果用户尝试通过Excel或其他应用程序直接连接到服务器,该触发器将回滚连接。

假设您拥有应用程序的控制权并可以对其进行修改,则应用程序角色将完全按照您的要求执行操作。请参阅联机丛书中的sp_setapprole以开始学习。

你不能以你想要的方式完成这项工作

  • 用户连接在整个过程中都具有相同的凭据,但某些特定的作用域使用“执行为”
  • 您已经意识到,无法依靠APP_NAME()或HOST_NAME()来检测何时有人以不同方式连接,这意味着每个表的回滚触发器不能依赖于此
  • 您的应用程序依赖于直接表写入访问
我能想到的一些选择

  • 您的应用程序使用存储的进程,用户只能对表进行读取访问
  • 在应用程序中使用SET CONTEXT_INFO为回滚触发器设置“secret”密钥
  • 将应用程序更改为使用服务帐户/是windows服务/etc,并在中代理用户名(如网页所示)
  • 。。。或者其他的一些排列

您确实需要首先决定如何组织和管理凭据

如果您使用sp_setapprole,将绕过Windows身份验证,并允许任何用户通过该应用进行访问。如果这是您真正想要做的,那么如果应用程序是服务器,请为该应用程序创建用户帐户,并在该用户的凭据下运行它

如果是客户端应用程序,则创建一个web服务,该服务将仅读取和发送应用程序需要的特定数据,并在新帐户下运行该web服务。然后,在IIS7中,您可以将ACL放在web服务本身上,以便它仍然受到保护


另外,如果不信任该应用程序是干净的,并且不知道它在做什么,则请求在允许其接触SQL server之前必须对其进行代码审查。如果是你自己的应用程序,那么开始相信自己:-)

嗯,我想我会采用这种方法。谢谢