上周公司有个妹子问了我一个关于SQL Server授权的问题,我没怎么玩过授权,不是很清楚。问题是这样的:如果用户A授权给用户B,用户B再授权给用户C,那么回收A的权限会不会把C的一起回收了。

我以前玩的都是在SQL Server中,给一个数据库添加Windows或者AD帐号,他们都是sysadmin角色,所以删除某个帐号并不影响别的帐号访问。这不适用于妹子的问题,所以今天我特地做了下测试。

测试内容:

用sa(SQL Server管理猿帐号)创建UserA, UserB。然后把SELECT News表的授权给UserA,再让UserA授权给UserB,最后回收UserA的权限,看看UserB还有木有权限。

首先,创建用户的脚本如下:

-- Create a SQL Server login named UserA, and then creates a corresponding database user UserA in TestDb.
CREATE LOGIN UserA WITH PASSWORD = 'aaa@123';
USE TestDb;
GO
CREATE USER UserA FOR LOGIN UserA;
GO

-- do the same for UserB
CREATE LOGIN UserB WITH PASSWORD = 'bbb@123';
USE TestDb;
GO
CREATE USER UserB FOR LOGIN UserB;
GO

这段脚本是以sa的身份运行的。运行成功后,刷新数据库可以看到Users里加入了UserA和UserB:

然后,我要给UserA授权,不然UserA登录数据库的时候,是看不见任何表的,也不能SELECT。

GRANT SELECT ON TestDb.dbo.News TO UserA

这条语句运行成功后,以UserA的身份登录数据库,就可以看见News表,并能够SELECT了:

但是,这时候如果试图用UserA的身份,给UserB授权,是要爆的:

这是因为之前给UserA授权的时候,并没有指定WITH GRANT OPTION。WITH GRANT的意思是,允许被授权的用户,把相同的权限授权给另一个用户。所以要回头更改给UserA授权的SQL语句为:

GRANT SELECT ON TestDb.dbo.News TO UserA WITH GRANT OPTION

现在,UserA就可以成功的把News表的SELECT权限传递给UserB了,并且UserB也可以成功的SELECT News表:

现在,我以sa的身份,回收UserA的权限,看看会发生什么?

SQL Server知道我给UserA授权的时候,用了WITH GRANT,所以它不允许我只回收UserA的权限。指定CASCADE选项的意思是,回收同时由WITH GRANT语句产生的传递授权,也就是同时回收UserB的SELECT权限。(UserB的这个SELECT权限,是由UserA的WITH GRANT产生的)

所以,在回收传递的权限时,必须在REVOKE语句的最后加上CASCADE:

-- do revoke
REVOKE SELECT ON TestDb.dbo.News TO UserA CASCADE

这样,UserA和UserB在News表上的SELECT权限会被一起回收。再次以UserA和UserB的身份运行SELECT语句,已经是拒绝访问的了:

结论:

在SQL Server中,要传递授权,必须加上WITH GRANT OPTION,并且,使用WITH GRANT OPTION的授权,在回收的时候必须加上CASCADE。(注意,这次测试仅仅是SQL Server,别的数据库很可能不一样)

妹子的问题也有了答案:如果用户A授权给用户B,用户B再授权给用户C(这里要用WITH GRANT OPTION允许B把权限给C),然后回收A的权限,C的权限是一起被回收的(因为必须加上CASCADE,没办法只回收A的权限)。