QSecurity 是 QPlugins 的安全相关插件接口及其实现, qplugins_security.pas 定义了安全相关的接口,我们在插件中使用时,只需要引用这个接口文件就可以了。而服务的实现单元并不包含在免费开源的范围内,如果您不想自己实现,或者想参考实现,需要付费购买,价格为人民币 99.00 元。
无论是我的实现,还是您自己去实现这些接口,它的用法是一样的,所以这个入门教程适合兼容于qplugins_security 接口的所有实现。
一、查找 IQSecurityService 服务
查找 IQSecurityService 服务接口和查找普通的服务是一样的,有多种方式:
- 如果你不知道服务的路径,那么直接通过 PluginsManager 来查找 IQSecurityService 实例即可,当然这并不是效率最高的方式,因为 PluginsManager 会遍历查找所有注册的接口及服务,以便找到它。但它是最易用的一种方式,在 Delphi 中,可以:
var AService:IQSecurityService; begin AService:=PluginsManager as IQSecurityService; .... end;
或者
var AService:IQSecurityService; begin if Supports(PluginsManager ,IQSecurityService ,AService then begin .... end; end;
或者:
var AService:IQSecurityService; begin if PluginsManager.QueryInterface(IQSecurityService ,AService)=S_OK then begin .... end; end;
当然,这几种方式本身没啥优劣之分,第一种要求服务必需已经注册才能使用,而后两种都会判定是否存在相应的接口。如果确认支持相应的服务,那就放心使用第一种方式,它在 Delphi 中最方便。
- 如果您知道服务的路径,按注册路径查找更快一些,我实现的服务注册路径为 /Services/Security,所以像下面这样子调用:
var AService:IQSecurityService; begin AService:=PluginsManager.ByPath('/Services/Security') as IQSecurityService; .... end;
二、注册自己模块的权限
对于松散耦合的应用开发来说,你永远不知道啥时候增加啥模块,而增加模块就意味着可能增加新权限项目。QPlugins Security 模块将这一步交由插件自身,“自事自知”,通过启动时注册自己的权限,然后授权模块就可以为用户进行授权。
一个简单的例子(我们继续接上面的 AService)是安全管理服务注册自己的权限:
- 定义权限的ID,它是一个GUID编码,你自己模块随意定义就可以,不需要关心其它模块的定义,毕竟你用 Ctrl+Shift+G 生成的随机的 GUID 编码与其它人定义重复的可能性很低。这个 ID 是你程序中检查权限的基础,一般我们会为权限进行分组,象下面的示例中,定义的是一个分组ID,两个子项权限:
const // 角色及权限管理分组ID SID_SECURITY_GROUP: TGuid = '{110CA18E-4B52-4D75-B3F3-9C99DC2B76FE}'; // 查看其它用户账号及权限 SID_SECURITY_VIEW: TGuid = '{B02A4134-3563-42A0-825E-C90BB5DD031E}'; // // 修改其它用户账号及权限等资料 SID_SECURITY_EDIT: TGuid = '{800896A0-E733-48BB-8CB4-857EC83F6F89}';
- 在插件的 initialization 里,注册权限:
var ARights:IQSecurityRights; AService:IQSecurityService; begin with PluginsManager as IQSecurityService do begin //注册分组 ARights:=IQSecurityRights(GetRootRight).AddGroup(SID_SECURITY_GROUP, '账号及权限管理', TQAccessRight.arDeny); //注册子权限 ARights.AddRight(SID_SECURITY_VIEW, '查看存在的账号及角色信息', TQAccessRight.arDeny); ARights.AddRight(SID_SECURITY_EDIT, '管理账号、角色及其权限', TQAccessRight.arDeny); end; end;
注册完成后,内存中就有了相应的权限对象。
三、判断当前用户权限
在需要判断权限的地方,通过 IQSecurityService.CanAccess 即可,比如:
with PluginsManager as IQSecurityService do begin btnView.Visible:=CanAccess(SID_SECURITY_VIEW); btnEdit.Visible:=CanAccess(SID_SECURITY_EDIT); end;
QSecurity 用户权限检验的规则说明如下:
- 用户如果未登录,则根据权限对象默认权限定义返回;如果默认权限不是明确的允许或拒绝,则继承自全局的默认权限。在我的实现中,它是拒绝。如果你确定某个权限默认开通,那你可以在上一步注册权限时,将默认权限设置为 arAllow 即可。
- 如果用户已经登录,则根据以下规则执行:
(1)在当前登录用户级别上,明确了允许还是拒绝,则返回明确的结果;如果没有,则检查有没有明确允许其父权限分组定义,如果仍没有,则遍历自己父角色执行同样的操作,以最终确定权限。
(2)如果当前用户多个父角色对同一对象的访问权限有冲突,那么按用户未登录时,检查权限的规则来处理。
四、注消权限注册
QSecurity 不支持权限的注销,也不需要插件释放相关的权限对象实例。
五、对插件修改当前用户权限的支持
出于安全原因,QSecurity 不允许其它插件去修改权限,相关的接口也不公开给其它插件使用。要修改当前用户的权限,通过 IQSecurityService 的 Config 接口来打开权限管理界面来修改。如果当前登录用户权限发生变动,还会发送 SNotify_RightsChanged 通知。
更多接口说明,请参考 qplugins_security 中相关接口函数的说明。