답변:
SQL Server 보안 모델을 사용하면 기본 테이블에 대한 액세스 권한을 부여하지 않고도 뷰에 대한 액세스 권한을 부여 할 수 있습니다.
예제 코드는 개념을 보여주는 좋은 방법이므로 LoginDetails
테이블과 해당 뷰를 사용하여 다음을 고려하십시오 .
CREATE TABLE dbo.LoginDetails
(
Username nvarchar(100) NOT NULL
, EmailAddress nvarchar(256) NOT NULL
, LastLoggedInAt datetime NULL
);
GO
CREATE VIEW dbo.LoginDetailsView
AS
SELECT ld.Username
, ld.EmailAddress
, ld.LastLoggedInAt
FROM dbo.LoginDetails ld
WHERE ld.LastLoggedInAt IS NOT NULL;
GO
로그인과 사용자를 생성 한 다음 테이블 자체를 볼 수있는 권한없이 해당 사용자에게보기에서 행을 선택할 수있는 권한을 할당합니다.
CREATE LOGIN RemoteUser
WITH PASSWORD = '2q1345lkjsadfgsa0(*';
CREATE USER RemoteUser
FOR LOGIN RemoteUser
WITH DEFAULT_SCHEMA = dbo;
GRANT SELECT ON dbo.LoginDetailsView TO RemoteUser;
이제 두 개의 테스트 행을 삽입합니다.
INSERT INTO dbo.LoginDetails(Username, EmailAddress, LastLoggedInAt)
VALUES ('user x', 'x@y.com', NULL)
, ('user y', 'y@y.com', GETDATE());
보안 모델을 테스트합니다. 첫 번째 SELECT
명령문은보기에서 선택하기 때문에 성공하지만 두 번째 SELECT
명령문은 사용자가 테이블에 직접 액세스 할 수 없으므로 실패합니다.
EXECUTE AS LOGIN = 'RemoteUser';
SELECT *
FROM dbo.LoginDetailsView;
╔ =========== ╦ ======================================= == ╗ ║ 사용자 이름 ║ 이메일 주소 ║ LastLoggedInAt ║ ╠ =========== ╬ ======================================= == ╣ ║ 사용자 y ║ y@y.com ║ 2018-02-15 07 : 36 : 54.490 ║ ╚ =========== ╩ ======================================= == ╝
SELECT *
FROM dbo.LoginDetails;
REVERT
뷰의 결과는 질문에 필요한 LastLoggedInAt
값이 NULL
인 행을 제외합니다 .
SELECT
기본 테이블에 대한 두 번째 문은 오류를 반환합니다.
메시지 229, 수준 14, 상태 5, 줄 28
개체 'LoginDetails', 데이터베이스 'tempdb', 스키마 'dbo'에 대한 SELECT 권한이 거부되었습니다.
대청소:
DROP USER RemoteUser;
DROP LOGIN RemoteUser;
DROP VIEW dbo.LoginDetailsView;
DROP TABLE dbo.LoginDetails;
또는 SQL Server 2016 이상을 사용하는 경우 행 수준 보안 조건자를 사용하여 특정 사용자가 NULL LastLoggedInAt
값을 가진 행을 보지 못하게 할 수 있습니다.
먼저 테이블, 로그인, 해당 로그인 사용자를 작성하고 테이블에 대한 액세스 권한을 부여합니다.
CREATE TABLE dbo.LoginDetails
(
Username nvarchar(100) NOT NULL
, EmailAddress nvarchar(256) NOT NULL
, LastLoggedInAt datetime NULL
);
GO
CREATE LOGIN RemoteUser
WITH PASSWORD = '2q1345lkjsadfgsa0(*';
CREATE USER RemoteUser
FOR LOGIN RemoteUser
WITH DEFAULT_SCHEMA = dbo;
GRANT SELECT ON dbo.LoginDetails TO RemoteUser;
다음으로 몇 개의 샘플 행을 삽입합니다. 하나의 행은 null LastLoggedInAt
이고 다른 하나는 해당 열에 대해 널이 아닌 값입니다.
INSERT INTO dbo.LoginDetails(Username, EmailAddress, LastLoggedInAt)
VALUES ('user x', 'x@y.com', NULL)
, ('user y', 'y@y.com', GETDATE());
여기에서는 함수 에 전달 된 @LastLoggedInAt
및 @username
변수 값에 따라 0 또는 1의 행을 반환하는 스키마 바운드 테이블 반환 함수를 만들고 있습니다. 이 함수는 필터 술어에 의해 사용되어 특정 사용자로부터 숨길 행을 제거합니다.
CREATE FUNCTION dbo.fn_LoginDetailsRemoteUserPredicate
(
@LastLoggedInAt datetime
, @username sysname
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN SELECT 1 AS fn_securitypredicate_result
WHERE (@username = N'RemoteUser' AND @LastLoggedInAt IS NOT NULL)
OR @username <> N'RemoteUser';
GO
이것은 테이블 SELECT
에 대해 실행 된 명령문 에서 행을 제거하는 보안 필터입니다 dbo.LoginDetails
.
CREATE SECURITY POLICY LoginDetailsRemoteUserPolicy
ADD FILTER PREDICATE dbo.fn_LoginDetailsRemoteUserPredicate(LastLoggedInAt, USER_NAME())
ON dbo.LoginDetails
WITH (STATE=ON);
위의 필터 는 테이블 dbo.fn_LoginDetailsRemoteUserPredicate
의 LastLoggedInAt
열에 대한 각 행의 값과 함께 현재 사용자의 이름을 전달 하여 함수를 사용 dbo.LoginDetails
합니다.
일반 사용자로 테이블을 쿼리하는 경우 :
SELECT *
FROM dbo.LoginDetails
우리는 모든 행을 본다 :
╔ =========== ╦ ======================================= == ╗ ║ 사용자 이름 ║ 이메일 주소 ║ LastLoggedInAt ║ ╠ =========== ╬ ======================================= == ╣ ║ 사용자 x ║ x@y.com ║ NULL ║ y 사용자 y ║ y@y.com ║ 2018-02-15 13 : 53 : 42.577 ║ ╚ =========== ╩ ======================================= == ╝
그러나 다음과 같이 테스트하면 RemoteUser
:
EXECUTE AS LOGIN = 'RemoteUser';
SELECT *
FROM dbo.LoginDetails
REVERT
"유효한"행만 볼 수 있습니다 :
╔ =========== ╦ ======================================= == ╗ ║ 사용자 이름 ║ 이메일 주소 ║ LastLoggedInAt ║ ╠ =========== ╬ ======================================= == ╣ ║ 사용자 y ║ y@y.com ║ 2018-02-15 13 : 42 : 02.023 ║ ╚ =========== ╩ ======================================= == ╝
그리고 우리는 정리합니다 :
DROP SECURITY POLICY LoginDetailsRemoteUserPolicy;
DROP FUNCTION dbo.fn_LoginDetailsRemoteUserPredicate;
DROP USER RemoteUser;
DROP LOGIN RemoteUser;
DROP TABLE dbo.LoginDetails;
이러한 방식으로 함수를 테이블에 스키마 바인딩하면 먼저 필터 술어와 dbo.fn_LoginDetailsRemoteUserPredicate
함수를 삭제하지 않고 테이블의 정의를 수정할 수 없습니다 .
LastLoggedInAt
컬럼 에 유용한 인덱스를 작성한다고 가정 할 때 성능에 거의 영향을 미치지 않습니다.