在前面有关如何使用kbmMW建立REST服务器的基础上,如今已经到了考虑该如何控制用户的访问。什么是访问管理?就是“容许谁作什么"的问题。
显然,这个世界中存在数据,应该保护他而不被未受权的人/进程来读取,建立或更改。反过来讲,这些数据应该获得保护,只有信任的人/进程才能够访问。另外,有的数据能够被人或进程来访问,但不容许被修改等等。
幸运的是,kbmMW内置了一些功能来解决上面的问题,核心是TkbmMWAuthorizationManager类。
首先在main form中添加一个TkbmMWAuthorizationManager(前文中的Unit7单元)。html
咱们能够单独使用受权管理器(authorization manager),但一般是经过kbmMWServer实例使用他,因此,将kbmMWServer1.AuthorizationManager属性设置为kbmMWAuthorizationManager1,
这样,受权管理器(authorization manager)将检查每次对应用程序服务器的访问权限。数据库
kbmMW受权管理器是一个可理解为下面主题的实体:浏览器
resource(资源)基本上是你要为其添加某种保护的任意内容,它能够是数据库相关的,也能够是一个特定的对象,或者是你但愿的功能或服务仅按你预期的方式处理,由你授予访问权限的人/进程处理。资源能够按资源树分组,容许访问其中一个资源,则自动容许访问该资源下的子资源。
actor一般是一我的(或一我的的登陆凭证),一个过程或其余标识“某人”的人,他们想要访问您的资源。
role是一种对通常访问模式进行分类的方法。图书馆中的role多是图书管理员,管理员和借用者。银行中的role能够是客户,出纳员,职员,管理员等等。这个想法是每一个role对各类资源都有不一样的访问权限。actor一般至少会被赋予一个role。actor能够拥有不一样的role,例如:取决于actor登陆的方式或来自哪里。
authorization是做为参与者或特定资源上的role运行的“许可”。authorization能够是否认的,如拒绝对特定资源及其子树的参与者或role访问。
constraint(约束)是对受权或登陆的限制。受权可能仅在特定时间范围内有效,或者容许从特定设备等访问,或者登陆只能在白天等进行。
login(登陆)是actor/password和登陆令牌之间的匹配。当actor试图登陆时,系统会验证登陆名,密码,请求的角色以及与登陆相关的任何约束。只有在检查完全部内容并容许登陆后,才会发出令牌(Token), 对基于kbmMW的服务器发出的每一个请求,actor /user/process须要发送Token。
综上所述,让咱们来定义两个想要访问REST服务器的角色(role),并将它们命名为“Reader”和“ReadWriter”,但因为kbmMW对角色命名(以及角色和资源)没有任何限制,只要名称在其类别中是惟一的,咱们就能够为它们命名(角色,演员,资源)。服务器
用代码来定义上面说的两个角色(role)Reader与ReadWriter(能够写在main form的OnCreate事件中):wordpress
kbmMWAuthorizationManager1.AddRole('READER'); kbmMWAuthorizationManager1.AddRole('READWRITER');
咱们还须要告诉受权管理器哪些参与者存在,以便它能够与演员匹配以尝试登陆。函数
简单的方法是将它们预约义给受权管理器。一样,能够写在main form的OnCreate事件中,也能够写在第一次访问服务器以前的其余地方。按你的实际状况,利用数据库或配置文件或LDAP等定义actor。网站
kbmMWAuthorizationManager1.AddActor('HANS','HANSPASSWORD','READER'); kbmMWAuthorizationManager1.AddActor('CHRISTINE','CHRISTINEPASSWORD','READWRITER');
这里定义了两个参与者的密码,若是他们没有特别要求不一样的角色,他们应该在登陆时肯定了扮演的角色。
有可能不预约义actor,取而代之使用事件处理程序,即经过kbmMWAuthorizationManager1实例的OnLogin事件验证它们是否存在于不一样的系统中。spa
procedure TForm7.kbmMWAuthorizationManager1Login(Sender: TObject; const AActorName, ARoleName: string; var APassPhrase: string; var AActor: TkbmMWAuthorizationActor; var ARole: TkbmMWAuthorizationRole; var AMessage: string); begin ... end;
一个AActorName与其请求的角色名称由ARoleName提供。可选地,若是actor name 为kbmMW已知,则还能够提供actor实例。若是没有,AActor为nil,若是你知道actor则必须由你建立。rest
ARole多是nil,若是它是一个被请求的未知角色。能够选择经过返回新建立的TkbmMWAuthorizationRole实例来动态创建角色。但请记住在返回以前,将任何新建立的actor或角色实例添加到kbmMWAuthorizationManagers的Actors和Roles列表属性中。code
APassword将包含登陆尝试时提供的密码。您能够动态修改它(例如将其更改成SHA256 hash,这样,受权管理器中将不存储明文密码)。
若是您为AActor或ARole返回nil ,则表示登陆失败。若是须要,能够在AMessage参数中提供说明。
让咱们继续为这个例子,定义一个简单的actor。
如今咱们已定义了actors和roles,受权管理器已准备好处理登陆尝试。
登陆只有一种方法,即经过调用受权管理器的Login方法。例如,能够从REST服务中的新REST函数调用它。
另外一种方法是让kbmMW自动检测登陆尝试,并为您调用Login方法。为此,请将kbmMWAutorizationManager1的Options属性设置为[ mwaoAutoLogin ]。
您可能还记得,对kbmMW服务器的全部请求都必须附带一个标识有效登陆的令牌。若是该令牌不可用,则使用从调用者传递的任何用户名/密码做为登陆尝试的数据触发kbmMW(设置了mwaoAutoLogin),并在登陆成功时将令牌返回给被调用者。
因为REST服务器本质上是一个Web服务器,遵循HTTP协议标准,当kbmMW检测到无效(或不存在)登陆时会发生什么,kbmMW将引起一个EkbmMWAuthException,反过来(当调用来自REST时) streamformat),将被转换为HTTP错误401,呈现给调用者。实际上,若是您在业务代码中的任何位置引起该异常而且您本身无论理它,它将自动做为401转发给调用者。
这将提示大多数浏览器提供登陆对话框,其中能够输入用户名/密码,而后下一次调用回服务器,将包括该登陆信息。kbmMW将自动检测并使用它。
因此咱们有演员,角色和登陆。如今咱们须要肯定咱们拥有哪些资源。资源能够是您要标记惟一名称的任何内容。
大多数状况下,将REST方法定义为资源是有意义的。使用kbmMW_Auth属性,让咱们在smart service中很是容易完成。咱们拥有操做和检索联系人的功能(Unit8)。
[kbmMW_Service('name:MyREST, flags:[listed]')] [kbmMW_Rest('path:/MyREST')] TkbmMWCustomSmartService8 = class(TkbmMWCustomSmartService) public [kbmMW_Auth('role:[READER,READWRITER], grant:true')] [kbmMW_Rest('method:get, path:helloworld, anonymousResult:true')] [kbmMW_Method] function HelloWorld:TMyResult; [kbmMW_Auth('role:[READER,READWRITER], grant:true')] [kbmMW_Rest('method:get, path:contacts, anonymousResult:true')] function GetContacts:TObjectList; [kbmMW_Auth('role:[READWRITER], grant:true')] [kbmMW_Rest('method:put, path:addcontact')] function AddContact([kbmMW_Rest('value:"{$name}"')] const AName:string; [kbmMW_Rest('value:"{$address}"')] const AAddress:string; [kbmMW_Rest('value:"{$zipcode}"')] const AZipCode:string; [kbmMW_Rest('value:"{$city}"')] const ACity:string):string; overload; [kbmMW_Auth('role:[READWRITER], grant:true')] [kbmMW_Rest('method:get, path:"addcontact/{name}"')] function AddContact([kbmMW_Rest('value:"{name}"')] const AName:string):string; overload; [kbmMW_Auth('role:[READWRITER], grant:true')] [kbmMW_Rest('method:delete, path:"contact/{id}"')] function DeleteContact([kbmMW_Rest('value:"{id}"')] const AID:string):boolean; end;
幕后发生的事情是kbmMW自动为这些函数定义资源名称:MyREST..AddContect,MyREST..GetContacts等。
额外注意一点:若是咱们为定义的Service定义了版本,当咱们创建他时,在中间应放一个“."。
如你所见,资源名称只是一个字符串,您能够本身定义所需的全部资源,但若是你用smart service,能够用上面的格式自动定义资源名称。
kbmMW还将自动要求受权管理员在任何客户端的呼叫时验证是否容许使用资源。
您能够选择经过手动调用受权管理器来进行更细粒度的受权,以验证调用,以下所示:
var res:TkbmMWAuthorizationStatus; sMessage:string; begin ... res:=AuthorizationManager1.IsAuthorized(logintoken, 'YOURRESOURCENAME', sMessage);
res返回mwasAuthorized,mwasNotAuthorized或mwasConstrained 。
mwasConstained意味着受权能够在不一样的状况下(不一样的时间或相似的时间)给出。返回的sMessage能够更详细地解释访问被拒绝的缘由。
在kbmMW智能服务(smart service)中,您能够获取登陆令牌(logintoken)做为方法的参数,以下所示:
[kbmMW_Auth('role:[READER], grant:true')] [kbmMW_Rest('method:get, path:"someCall"')] function SomeCall([kbmMW_Arg(mwatToken)] const AToken:string):boolean;
调用SomeCall方法时,其AToken参数包含logintoken。
若是您不但愿令牌成为方法调用的参数列表的一部分,您也能够在方法中访问ClientIdentity.Token属性。
如今,您的REST服务器受SSL保护,并经过登陆调用其功能。
受权管理器中有许多功能,我在这里没有解释,但能够访问咱们的网站http://www.components4developers.com,查找kbmMW白皮书相关部分。
原文地址:https://components4developers.blog/2017/05/26/rest-easy-with-kbmmw-4-access-management/
做者相关的博文: