【问题标题】:Update statement with nontouchable field使用不可触摸字段更新语句
【发布时间】:2012-02-19 07:24:47
【问题描述】:

我有 mssql2008 r2 sql server

问题: 用户对表有一些列权限。他可以更新表的某些列(不是全部)。我们需要创建 UPDATE 语句,这样它就不会违反权限。 最好不要动态查询。

MSSQL server 有这个能力吗?

【问题讨论】:

    标签: sql sql-server-2008 tsql database-permissions


    【解决方案1】:

    没有动态 SQL(或应用或 API 层中的动态查询构造)?我不认为它会很漂亮。 UPDATE 命令不知道用户可能对受影响的列拥有什么权限。它将向引擎提交查询并希望获得最好的结果。如果用户没有对所有列的权限,它将返回一个错误,而不是试图通过改变预期的语句来规避它。我认为继续更新实际上是一件非常糟糕的事情,即使并非所有预期的列都已更新。

    话虽如此,我想你可以做这样的事情,但它根本不会漂亮 - 事实上,如果你不依赖数据库主体,它会容易得多:

    DECLARE 
        @dpid INT = DATABASE_PRINCIPAL_ID(),
        @obj  INT = OBJECT_ID('dbo.foo'),
        @col  SYSNAME = N'bar';
    
    UPDATE dbo.foo SET bar = CASE 
      WHEN EXISTS -- check they've been granted UPDATE at column or table level:
      (
        SELECT 1 
          FROM sys.database_permissions AS dp
          INNER JOIN sys.objects AS o 
            ON dp.major_id = o.[object_id]
          LEFT OUTER JOIN  sys.columns AS c
            ON dp.minor_id = COALESCE(c.column_id, 0)
          WHERE dp.grantee_principal_id = @dpid
          AND o.[object_id] = @obj
          AND (c.name = @col OR c.column_id IS NULL)
          AND dp.[permission_name] = 'UPDATE'
          AND dp.[state] = 'G' -- GRANT
      ) 
      AND NOT EXISTS -- since DENY trumps GRANT, make sure that doesn't also exist:
      (
        SELECT 1
          FROM sys.database_permissions AS dp
          INNER JOIN sys.objects AS o
            ON dp.major_id = o.[object_id]
          LEFT OUTER JOIN  sys.columns AS c
            ON dp.minor_id = COALESCE(c.column_id, 0)
          WHERE dp.grantee_principal_id = @dpid
          AND o.[object_id] = @obj
          AND (c.name = @col OR c.column_id IS NULL)
          AND dp.[permission_name] = 'UPDATE'
          AND dp.[state] = 'D' -- DENY
    )
    THEN @bar ELSE bar END
    -- WHERE...
    ;
    

    这并不是您所要求的;从技术上讲,它会更新列,但会将其设置为自身(例如,它仍将在触发器中指示为更新的列),但它会阻止将输入应用于表。除了对指定用户或角色的显式 GRANT UPDATE 或 DENY UPDATE 之外,我也没有检查以其他方式授予的权限——例如​​ GRANT ALL 或 AD 组成员身份继承的权限,这会使情况复杂化。当然,如果您有多个列要检查,那么管理它一点也不好玩。

    您可能希望在 WHEN 子句中添加其他条件,例如为了避免检查 dbo (who ) 或您想要明确绕过检查的用户,您可以:

    CASE 
      WHEN DATABASE_PRINCIPAL_ID() = 1 THEN @bar
      WHEN SUSER_SNAME = 'some_user' THEN @bar
      WHEN (...stuff from above...)
      ELSE bar
    END
    -- WHERE...
    ;
    

    【讨论】:

    • 是的,当然,UPDATE 不知道,但我可以告诉 UPDATE 不要显式更改(触摸)特定列吗?
    • 是的,不将它们包含在子句中?你不能说UPDATE foo SET bar = bar + 1 WITH BUT_DO_NOT_TOUCH_THIS...
    • 别笑我:-) 好的,我明白了,我明白你的回答和评论。也许你可以建议我在他的情况下我应该怎么做(基于你的观点),不是吗?
    • 当然,检查用户确实可以访问哪些列,并动态构建查询。您必须让他们知道并非他们的所有数据都被接受。或者,仅向用户展示他/她可以更改的列提供输入的能力(例如,通过使他们无法编辑的表单字段变灰/只读)。那么就没有惊喜了。
    猜你喜欢
    • 2013-04-11
    • 1970-01-01
    • 2018-02-28
    • 2019-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-08
    相关资源
    最近更新 更多