0

我有 mssql2008 r2 sql server

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

MSSQL 服务器有这个能力吗?

4

1 回答 1

2

没有动态 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...
;
于 2012-01-26T05:01:12.280 回答