代码之家  ›  专栏  ›  技术社区  ›  René

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

  •  2
  • René  · 技术社区  · 16 年前

    我在使用混合模式身份验证的Microsoft SQL Server 2008 Express实例中有一个名为mydb的数据库。使用数据库mydb的应用程序当前使用当前用户的Windows凭据通过Windows身份验证进行连接。此登录名是“public”服务器角色的成员,并且在mydb数据库中有一个映射到该角色的用户。此数据库用户是db_datareader和db_datawriter数据库角色的成员。

    我想要的是,当应用程序连接时,它具有在mydb中读写的权限。但是当另一个应用程序使用相同的登录名连接时,应该只允许读取。

    我的想法是创建一个登录触发器,它将检查连接字符串中的应用程序名部分,并基于此决定是否应该切换执行上下文。(对于记录,我知道依赖连接字符串的应用程序名是不安全的,而且很容易规避。这里的目的不是保护数据库,而是帮助用户在使用其他应用程序(如Microsoft Excel)连接时避免更改数据)

    我创建了一个名为“myapp\u reader”的新登录名,它映射到mydb数据库中的一个用户,该用户是db\u 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”失败。
    已将数据库上下文更改为“master”。
    已将语言设置更改为“美国英语”。(Microsoft SQL Server,错误:17892)

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

    错误:15590,严重性:16,状态:1。
    只能将“no revert”或“cookie”选项与临时级别的“execute as”语句一起使用。
    错误:17892,严重性:20,状态:1。
    由于触发器执行,登录“mycomputer\mywindowsusername”失败。[客户:XXX.XXX.XXX.XXX]

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

    4 回复  |  直到 16 年前
        1
  •  1
  •   Nick    16 年前

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

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

        2
  •  1
  •   Pondlife    16 年前

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

        3
  •  0
  •   gbn    16 年前

    你不能按你想要的方式来做。

    • 除了使用EXECUTE AS的某些特定作用域之外,用户连接在整个过程中具有相同的凭据。
    • 您已经意识到,不能依靠app_name()或host_name()来检测某人的连接是否不同,这意味着每个表都不能依赖回滚触发器。
    • 您的应用程序依赖于直接表写入访问

    我能想到的一些选择…

    • 您的应用程序使用存储的进程,用户只能读取表
    • 使用应用程序中的set context_info为回滚触发器设置“secret”键
    • 将应用程序更改为使用服务帐户/是Windows服务/etc,并在中代理用户名(就像网页一样)
    • …或者其他的排列
        4
  •  0
  •   ZXX    16 年前

    您真的需要先决定如何组织和管理凭证。

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

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

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