0

We're using stored procedures to restrict the access of some of our database users. They need access to specific parts of the database (not just tables/views, but also specific rows), and the sproc should check if the user is allowed to see the table rows he's requesting.

To store the authorization rules, we're planning to use a table dbo.AuthRules like that:

|ID|UserId  |AccessFrom  |AccessTo    | ...
===============================================
| 1|       1| 01.01.2013 | 31.12.2013 | ...
| 2|       2| 31.05.2012 | 31.12.2015 | ...

The stored procedure would then query that table to check if the current user has access to the requested data. To make it clear: We cannot just use GRANT PERMISSION because we need fine-grained access rules down to the rows in the DB.

We're not sure about the UserId column. The best solution would be some kind of foreign key to the system view sys.database_principals, but there are no foreign keys to views.

  • Should we just store the principal_id column of sys.database_principals, without any constraint?
  • Would it be better to store the name column instead of principal_id?
  • Are there other options to store a reference to the DB user?
4

2 回答 2

1

问:我们是否应该只存储 sys.database_principals 的 principal_id 列,没有任何约束?

答:如果您只评估基于约束的解决方案,那么您实际上别无选择。但是,如果您愿意编写触发器,那将是至少“虚拟”创建约束的方法。否则,您将不得不参考系统sysowners表,如果没有一些黑客攻击,这是不可能的。

问:存储名称列而不是principal_id会更好吗?

答:要回答这个问题,您必须提出假设问题。如果 principal_id 发生变化怎么办?如果改名怎么办?更新/删除呢?我总是宁愿有一个基于 id 的解决方案。

问:还有其他选项可以存储对 DB 用户的引用吗?

答:如答案#1 中所述,我认为除了创建触发器之外没有任何可能性......

于 2013-07-23T09:33:18.940 回答
1

考虑这种设计方法。

USE "master";

-- Create our test logins (don't forget to tidy these up later!)
CREATE LOGIN "batman"
  WITH PASSWORD = N''
     , CHECK_EXPIRATION = OFF
     , CHECK_POLICY = OFF;

CREATE LOGIN "robin"
  WITH PASSWORD = N''
     , CHECK_EXPIRATION = OFF
     , CHECK_POLICY = OFF;

USE "playdb";

-- Create the corresponding users
CREATE USER "batman"
  FOR LOGIN "batman";

CREATE USER "robin"
  FOR LOGIN "robin";

-- Grant them some select permissions
EXEC sp_addrolemember N'db_datareader', N'batman';
EXEC sp_addrolemember N'db_datareader', N'robin';

-- Create our "user access" table
DECLARE @users table (
   username    sysname NOT NULL
 , access_from date    NOT NULL DEFAULT '1900-01-01' -- Deliberately not allowing nulls and setting the widest possible value range
 , access_to   date    NOT NULL DEFAULT '9999-12-31' --   this will make our queries so much easier!
);

-- Give one user full permissions
INSERT INTO @users (username)
  VALUES ('batman');

-- Limit what this chappy can see
INSERT INTO @users (username, access_from, access_to)
  VALUES ('robin', '2011-01-01', '2012-01-01');

-- Example data table
DECLARE @data table (
  date_field date NOT NULL
);
-- ...with example data
INSERT INTO @data (date_field)
  VALUES ('2010-01-01')
       , ('2011-01-01')
       , ('2012-01-01')
       , ('2012-01-01')
       , ('2013-01-01')
       , ('2014-01-01');

-- Let's mimic our full access user
SETUSER 'batman';

SELECT System_User As current_username
     , *
FROM   @data As data
WHERE  EXISTS ( -- Limit the records to only those this user is allowed to see
         SELECT *
         FROM   @users
         WHERE  username = System_User
         AND    data.date_field >= access_from
         AND    data.date_field <  access_to
       );

SETUSER; -- Reset user

-- Imitate the chap with restricted access
SETUSER 'robin';

-- Exacty same query as before
SELECT System_User As current_username
     , *
FROM   @data As data
WHERE  EXISTS (
         SELECT *
         FROM   @users
         WHERE  username = System_User
         AND    data.date_field >= access_from
         AND    data.date_field <  access_to
       );
于 2013-07-23T10:57:13.533 回答