diff --git a/404.html b/404.html index ea15f2f0..dcfb4b4d 100644 --- a/404.html +++ b/404.html @@ -5,7 +5,7 @@ Page Not Found | LmcRbacMvc - + diff --git a/assets/js/8b5d4ccc.f7b8e814.js b/assets/js/8b5d4ccc.972489eb.js similarity index 99% rename from assets/js/8b5d4ccc.f7b8e814.js rename to assets/js/8b5d4ccc.972489eb.js index 879550d2..e6508565 100644 --- a/assets/js/8b5d4ccc.f7b8e814.js +++ b/assets/js/8b5d4ccc.972489eb.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[223],{82:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>i,contentTitle:()=>a,default:()=>d,frontMatter:()=>t,metadata:()=>l,toc:()=>A});var s=r(4848),o=r(8453);const t={sidebar_position:5},a="Guards",l={id:"guards",title:"Guards",description:"In this section, you will learn:",source:"@site/docs/guards.md",sourceDirName:".",slug:"/guards",permalink:"/LmcRbacMvc/docs/guards",draft:!1,unlisted:!1,editUrl:"https://github.com/lm-commons/lmcrbacmvc/tree/master/docs/docs/guards.md",tags:[],version:"current",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"tutorialSidebar",previous:{title:"Role providers",permalink:"/LmcRbacMvc/docs/role-providers"},next:{title:"Strategies",permalink:"/LmcRbacMvc/docs/strategies"}},i={},A=[{value:"What are guards and when should you use them?",id:"what-are-guards-and-when-should-you-use-them",level:2},{value:"Protection policy",id:"protection-policy",level:3},{value:"Built-in guards",id:"built-in-guards",level:2},{value:"RouteGuard",id:"routeguard",level:3},{value:"RoutePermissionsGuard",id:"routepermissionsguard",level:3},{value:"ControllerGuard",id:"controllerguard",level:3},{value:"ControllerPermissionsGuard",id:"controllerpermissionsguard",level:3},{value:"Security notice",id:"security-notice",level:3},{value:"Creating custom guards",id:"creating-custom-guards",level:2}];function c(e){const n={blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"guards",children:"Guards"}),"\n",(0,s.jsx)(n.p,{children:"In this section, you will learn:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"What guards are"}),"\n",(0,s.jsx)(n.li,{children:"How to use and configure built-in guards"}),"\n",(0,s.jsx)(n.li,{children:"How to create custom guards"}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"what-are-guards-and-when-should-you-use-them",children:"What are guards and when should you use them?"}),"\n",(0,s.jsx)(n.p,{children:"Guards are listeners that are registered on a specific event of\nthe MVC workflow. They allow your application to quickly mark a request as unauthorized."}),"\n",(0,s.jsx)(n.p,{children:"Here is a simple workflow without guards:"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.img,{alt:"Laminas Framework workflow without guards",src:r(4676).A+"",width:"920",height:"200"})}),"\n",(0,s.jsx)(n.p,{children:"And here is a simple workflow with a route guard:"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.img,{alt:"Laminas Framework workflow with guards",src:r(7376).A+"",width:"1120",height:"1600"})}),"\n",(0,s.jsx)(n.p,{children:'RouteGuard and ControllerGuard are not aware of permissions but rather only think about "roles". For\ninstance, you may want to refuse access to each routes that begin by "admin/*" to all users that do not have the\n"admin" role.'}),"\n",(0,s.jsx)(n.p,{children:'If you want to protect a route for a set of permissions, you must use RoutePermissionsGuard. For instance,\nyou may want to grant access to a route "post/delete" only to roles having the "delete" permission.\nNote that in a RBAC system, a permission is linked to a role, not to a user.'}),"\n",(0,s.jsx)(n.p,{children:"Albeit simple to use, guards should not be the only protection in your application, and you should always\nprotect your services as well. The reason is that your business logic should be handled by your service. Protecting a given\nroute or controller does not mean that the service cannot be access from elsewhere (another action for instance)."}),"\n",(0,s.jsx)(n.h3,{id:"protection-policy",children:"Protection policy"}),"\n",(0,s.jsx)(n.p,{children:'By default, when a guard is added, it will perform a check only on the specified guard rules. Any route or controller\nthat is not specified in the rules will be "granted" by default. Therefore, the default is a "blacklist"\nmechanism.'}),"\n",(0,s.jsx)(n.p,{children:'However, you may want a more restrictive approach (also called "whitelist"). In this mode, once a guard is added,\nanything that is not explicitly added will be refused by default.'}),"\n",(0,s.jsx)(n.p,{children:'For instance, let\'s say you have two routes: "index" and "login". If you specify a route guard rule to allow "index"\nroute to "member" role, your "login" route will become defacto unauthorized to anyone, unless you add a new rule for\nallowing the route "login" to "member" role.'}),"\n",(0,s.jsx)(n.p,{children:"You can change it in LmcRbacMvc config, as follows:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"use LmcRbacMvc\\Guard\\GuardInterface;\n\nreturn [\n 'lmc_rbac' => [\n 'protection_policy' => GuardInterface::POLICY_DENY\n ]\n];\n"})}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"NOTE: this policy will block ANY route/controller (so it will also block any console routes or controllers). The\ndeny policy is much more secure, but it needs much more configuration to work with."}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"built-in-guards",children:"Built-in guards"}),"\n",(0,s.jsx)(n.p,{children:"LmcRbacMvc comes with four guards, in order of priority :"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"RouteGuard : protect a set of routes based on the identity roles"}),"\n",(0,s.jsx)(n.li,{children:"RoutePermissionsGuard : protect a set of routes based on roles permissions"}),"\n",(0,s.jsx)(n.li,{children:"ControllerGuard : protect a controllers and/or actions based on the identity roles"}),"\n",(0,s.jsx)(n.li,{children:"ControllerPermissionsGuard : protect a controllers and/or actions based on roles permissions"}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["All guards must be added in the ",(0,s.jsx)(n.code,{children:"guards"})," subkey:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n // Guards config here!\n ]\n ]\n];\n"})}),"\n",(0,s.jsx)(n.p,{children:"Because of the way Laminas Framework handles config, you can without problem define some rules in one module, and\nmore rules in another module. All the rules will be automatically merged."}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:'For your mental health, I recommend you to use either the route guard OR the controller guard, but not both. If\nyou decide to use both conjointly, I recommend you to set the protection policy to "allow" (otherwise, you will\nneed to define rules for every routes AND every controller, which can become quite frustrating!).'}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["Please note that if your application uses both route and controller guards, route guards are always executed\n",(0,s.jsx)(n.strong,{children:"before"})," controller guards (they have a higher priority)."]}),"\n",(0,s.jsx)(n.h3,{id:"routeguard",children:"RouteGuard"}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsxs)(n.p,{children:["The RouteGuard listens to the ",(0,s.jsx)(n.code,{children:"MvcEvent::EVENT_ROUTE"})," event with a priority of -5."]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:'The RouteGuard allows your application to protect a route or a hierarchy of routes. You must provide an array of "key" => "value",\nwhere the key is a route pattern and the value is an array of role names:'}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\RouteGuard' => [\n 'admin*' => ['admin'],\n 'login' => ['guest']\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"Only one role in a rule needs to be matched (it is an OR condition)."}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:'Those rules grant access to all admin routes to users that have the "admin" role, and grant access to the "login"\nroute to users that have the "guest" role (eg.: most likely unauthenticated users).'}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"The route pattern is not a regex. It only supports the wildcard (*) character, that replaces any segment."}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"You can also use the wildcard character * for roles:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\RouteGuard' => [\n 'home' => ['*']\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsx)(n.p,{children:'This rule grants access to the "home" route to anyone.'}),"\n",(0,s.jsx)(n.p,{children:"Finally, you can also omit the roles array to completely block a route, for maintenance purpose for example :"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\RouteGuard' => [\n 'route_under_construction'\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsx)(n.p,{children:"This rule will be inaccessible."}),"\n",(0,s.jsx)(n.p,{children:"Note : this last example could be (and should be) written in a more explicit way :"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\RouteGuard' => [\n 'route_under_construction' => []\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsx)(n.h3,{id:"routepermissionsguard",children:"RoutePermissionsGuard"}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsxs)(n.p,{children:["The RoutePermissionsGuard listens to the ",(0,s.jsx)(n.code,{children:"MvcEvent::EVENT_ROUTE"})," event with a priority of -8."]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:'The RoutePermissionsGuard allows your application to protect a route or a hierarchy of routes. You must provide an array of "key" => "value",\nwhere the key is a route pattern and the value is an array of permission names:'}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\RoutePermissionsGuard' => [\n 'admin*' => ['admin'],\n 'post/manage' => ['post.update', 'post.delete']\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"By default, all permissions in a rule must be matched (an AND condition)."}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["In the previous example, one must have ",(0,s.jsx)(n.code,{children:"post.update"})," ",(0,s.jsx)(n.strong,{children:"AND"})," ",(0,s.jsx)(n.code,{children:"post.delete"})," permissions\nto access the ",(0,s.jsx)(n.code,{children:"post/manage"})," route. You can also specify an OR condition like so:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"use LmcRbacMvc\\Guard\\GuardInterface;\n\nreturn [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\RoutePermissionsGuard' => [\n 'post/manage' => [\n 'permissions' => ['post.update', 'post.delete'],\n 'condition' => GuardInterface::CONDITION_OR\n ]\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"Permissions are linked to roles, not to users"}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:'Those rules grant access to all admin routes to roles that have the "admin" permission, and grant access to the\n"post/delete" route to roles that have the "post.delete" or "admin" permissions.'}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"The route pattern is not a regex. It only supports the wildcard (*) character, that replaces any segment."}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"You can also use the wildcard character * for permissions:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\RoutePermissionsGuard' => [\n 'home' => ['*']\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsx)(n.p,{children:'This rule grants access to the "home" route to anyone.'}),"\n",(0,s.jsx)(n.p,{children:"Finally, you can also use an empty array to completly block a route, for maintenance purpose for example :"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\RoutePermissionsGuard' => [\n 'route_under_construction' => []\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsx)(n.p,{children:"This route will be inaccessible."}),"\n",(0,s.jsx)(n.h3,{id:"controllerguard",children:"ControllerGuard"}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsxs)(n.p,{children:["The ControllerGuard listens to the ",(0,s.jsx)(n.code,{children:"MvcEvent::EVENT_ROUTE"})," event with a priority of -10."]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"The ControllerGuard allows your application to protect a controller. You must provide an array of arrays:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\ControllerGuard' => [\n [\n 'controller' => 'MyController',\n 'roles' => ['guest', 'member']\n ]\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"Only one role in a rule need to be matched (it is an OR condition)."}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:'Those rules grant access to each actions of the MyController controller to users that have either the "guest" or\n"member" roles.'}),"\n",(0,s.jsx)(n.p,{children:"As for RouteGuard, you can use a wildcard (*) character for roles."}),"\n",(0,s.jsx)(n.p,{children:"You can also specify optional actions, so that the rule only apply to one or several actions:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\ControllerGuard' => [\n [\n 'controller' => 'MyController',\n 'actions' => ['read', 'edit'],\n 'roles' => ['guest', 'member']\n ]\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsx)(n.p,{children:"You can combine a generic rule and a specific action rule for the same controller, as follows:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\ControllerGuard' => [\n [\n 'controller' => 'PostController',\n 'roles' => ['member']\n ],\n [\n 'controller' => 'PostController',\n 'actions' => ['delete'],\n 'roles' => ['admin']\n ]\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsx)(n.p,{children:'These rules grant access to each controller action to users that have the "member" role, but restrict the\n"delete" action to "admin" only.'}),"\n",(0,s.jsx)(n.h3,{id:"controllerpermissionsguard",children:"ControllerPermissionsGuard"}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsxs)(n.p,{children:["The ControllerPermissionsGuard listens to the ",(0,s.jsx)(n.code,{children:"MvcEvent::EVENT_ROUTE"})," event with a priority of -13."]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"The ControllerPermissionsGuard allows your application to protect a controller using permissions. You must provide an array of arrays:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\ControllerPermissionsGuard' => [\n [\n 'controller' => 'MyController',\n 'permissions' => ['post.update', 'post.delete']\n ]\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"All permissions in a rule must be matched (it is an AND condition)."}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["In the previous example, the user must have ",(0,s.jsx)(n.code,{children:"post.update"})," ",(0,s.jsx)(n.strong,{children:"AND"})," ",(0,s.jsx)(n.code,{children:"post.delete"})," permissions\nto access each action of the MyController controller."]}),"\n",(0,s.jsx)(n.p,{children:"As for all other guards, you can use a wildcard (*) character for permissions."}),"\n",(0,s.jsx)(n.p,{children:"The configuration rules are the same as for ControllerGuard."}),"\n",(0,s.jsx)(n.h3,{id:"security-notice",children:"Security notice"}),"\n",(0,s.jsxs)(n.p,{children:["RouteGuard and ControllerGuard listen to the ",(0,s.jsx)(n.code,{children:"MvcEvent::EVENT_ROUTE"})," event. Therefore, if you use the\n",(0,s.jsx)(n.code,{children:"forward"})," method in your controller, those guards will not intercept and check requests (because internally\nLaminas MVC does not trigger again a new MVC loop)."]}),"\n",(0,s.jsx)(n.p,{children:"Most of the time, this is not an issue, but you must be aware of it, and this is an additional reason why you\nshould always protect your services too."}),"\n",(0,s.jsx)(n.h2,{id:"creating-custom-guards",children:"Creating custom guards"}),"\n",(0,s.jsx)(n.p,{children:"LmcRbacMvc is flexible enough to allow you to create custom guards. Let's say we want to create a guard that will\nrefuse access based on an IP addresses blacklist."}),"\n",(0,s.jsx)(n.p,{children:"First create the guard:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"namespace Application\\Guard;\n\nuse Laminas\\Http\\Request as HttpRequest;\nuse Laminas\\Mvc\\MvcEvent;\nuse LmcRbacMvc\\Guard\\AbstractGuard;\n\nclass IpGuard extends AbstractGuard\n{\n const EVENT_PRIORITY = 100;\n\n /**\n * List of IPs to blacklist\n */\n protected $ipAddresses = [];\n\n /**\n * @param array $ipAddresses\n */\n public function __construct(array $ipAddresses)\n {\n $this->ipAddresses = $ipAddresses;\n }\n\n /**\n * @param MvcEvent $event\n * @return bool\n */\n public function isGranted(MvcEvent $event)\n {\n $request = $event->getRequest();\n\n if (!$request instanceof HttpRequest) {\n return true;\n }\n\n $clientIp = $_SERVER['REMOTE_ADDR'];\n\n return !in_array($clientIp, $this->ipAddresses);\n }\n}\n"})}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsxs)(n.p,{children:["Guards must implement ",(0,s.jsx)(n.code,{children:"LmcRbacMvc\\Guard\\GuardInterface"}),"."]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["By default, guards are listening to the event ",(0,s.jsx)(n.code,{children:"MvcEvent::EVENT_ROUTE"})," with a priority of -5 (you can change the default\nevent to listen by overriding the ",(0,s.jsx)(n.code,{children:"EVENT_NAME"})," constant in your guard subclass). However, in this case, we don't\neven need to wait for the route to be matched, so we overload the ",(0,s.jsx)(n.code,{children:"EVENT_PRIORITY"})," constant to be executed earlier."]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"isGranted"})," method simply retrieves the client IP address, and checks it against the blacklist."]}),"\n",(0,s.jsx)(n.p,{children:"However, for this to work, we must register the newly created guard with the guard plugin manager. To do so, add the\nfollowing code in your config:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'zfc_rbac' => [\n 'guard_manager' => [\n 'factories' => [\n 'Application\\Guard\\IpGuard' => 'Application\\Factory\\IpGuardFactory'\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"guard_manager"})," config follows a conventional service manager configuration format."]}),"\n",(0,s.jsx)(n.p,{children:"Now, let's create the factory:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"namespace Application\\Factory;\n\nuse Application\\Guard\\IpGuard;\nuse Laminas\\ServiceManager\\Factory\\FactoryInterface;\nuse Laminas\\ServiceManager\\ServiceLocatorInterface;\n\nclass IpGuardFactory implements FactoryInterface\n{\n /**\n * {@inheritDoc}\n */\n public function __invoke(ContainerInterface $container, $requestedName, array $options = null)\n {\n if (null === $options) {\n $options = [];\n }\n return new IpGuard($options);\n }\n}\n"})}),"\n",(0,s.jsx)(n.p,{children:"In a real use case, you would likely fetched the blacklist from a database."}),"\n",(0,s.jsxs)(n.p,{children:["Now we just need to add the guard to the ",(0,s.jsx)(n.code,{children:"guards"})," option, so that LmcRbacMvc can execute the logic behind this guard. In\nyour config, add the following code:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'Application\\Guard\\IpGuard' => [\n '87.45.66.46',\n '65.87.35.43'\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The array of IP addresses will be passed to ",(0,s.jsx)(n.code,{children:"IpGuardFactory::__invoke"})," in the ",(0,s.jsx)(n.code,{children:"$options"})," parameter."]})]})}function d(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},7376:(e,n,r)=>{r.d(n,{A:()=>s});const s=r.p+"assets/images/workflow-with-guards-9421d2ccbded4218039d3c55d9e07d64.png"},4676:(e,n,r)=>{r.d(n,{A:()=>s});const s="data:image/png;base64,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"},8453:(e,n,r)=>{r.d(n,{R:()=>a,x:()=>l});var s=r(6540);const o={},t=s.createContext(o);function a(e){const n=s.useContext(t);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:a(e.components),s.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[223],{82:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>i,contentTitle:()=>a,default:()=>d,frontMatter:()=>t,metadata:()=>l,toc:()=>A});var s=r(4848),o=r(8453);const t={sidebar_position:5},a="Guards",l={id:"guards",title:"Guards",description:"In this section, you will learn:",source:"@site/docs/guards.md",sourceDirName:".",slug:"/guards",permalink:"/LmcRbacMvc/docs/guards",draft:!1,unlisted:!1,editUrl:"https://github.com/lm-commons/lmcrbacmvc/tree/master/docs/docs/guards.md",tags:[],version:"current",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"tutorialSidebar",previous:{title:"Role providers",permalink:"/LmcRbacMvc/docs/role-providers"},next:{title:"Strategies",permalink:"/LmcRbacMvc/docs/strategies"}},i={},A=[{value:"What are guards and when should you use them?",id:"what-are-guards-and-when-should-you-use-them",level:2},{value:"Protection policy",id:"protection-policy",level:3},{value:"Built-in guards",id:"built-in-guards",level:2},{value:"RouteGuard",id:"routeguard",level:3},{value:"RoutePermissionsGuard",id:"routepermissionsguard",level:3},{value:"ControllerGuard",id:"controllerguard",level:3},{value:"ControllerPermissionsGuard",id:"controllerpermissionsguard",level:3},{value:"Security notice",id:"security-notice",level:3},{value:"Creating custom guards",id:"creating-custom-guards",level:2}];function c(e){const n={blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"guards",children:"Guards"}),"\n",(0,s.jsx)(n.p,{children:"In this section, you will learn:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"What guards are"}),"\n",(0,s.jsx)(n.li,{children:"How to use and configure built-in guards"}),"\n",(0,s.jsx)(n.li,{children:"How to create custom guards"}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"what-are-guards-and-when-should-you-use-them",children:"What are guards and when should you use them?"}),"\n",(0,s.jsx)(n.p,{children:"Guards are listeners that are registered on a specific event of\nthe MVC workflow. They allow your application to quickly mark a request as unauthorized."}),"\n",(0,s.jsx)(n.p,{children:"Here is a simple workflow without guards:"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.img,{alt:"Laminas Framework workflow without guards",src:r(4676).A+"",width:"920",height:"200"})}),"\n",(0,s.jsx)(n.p,{children:"And here is a simple workflow with a route guard:"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.img,{alt:"Laminas Framework workflow with guards",src:r(7376).A+"",width:"1120",height:"1600"})}),"\n",(0,s.jsx)(n.p,{children:'RouteGuard and ControllerGuard are not aware of permissions but rather only think about "roles". For\ninstance, you may want to refuse access to each routes that begin by "admin/*" to all users that do not have the\n"admin" role.'}),"\n",(0,s.jsx)(n.p,{children:'If you want to protect a route for a set of permissions, you must use RoutePermissionsGuard. For instance,\nyou may want to grant access to a route "post/delete" only to roles having the "delete" permission.\nNote that in a RBAC system, a permission is linked to a role, not to a user.'}),"\n",(0,s.jsx)(n.p,{children:"Albeit simple to use, guards should not be the only protection in your application, and you should always\nprotect your services as well. The reason is that your business logic should be handled by your service. Protecting a given\nroute or controller does not mean that the service cannot be access from elsewhere (another action for instance)."}),"\n",(0,s.jsx)(n.h3,{id:"protection-policy",children:"Protection policy"}),"\n",(0,s.jsx)(n.p,{children:'By default, when a guard is added, it will perform a check only on the specified guard rules. Any route or controller\nthat is not specified in the rules will be "granted" by default. Therefore, the default is a "blacklist"\nmechanism.'}),"\n",(0,s.jsx)(n.p,{children:'However, you may want a more restrictive approach (also called "whitelist"). In this mode, once a guard is added,\nanything that is not explicitly added will be refused by default.'}),"\n",(0,s.jsx)(n.p,{children:'For instance, let\'s say you have two routes: "index" and "login". If you specify a route guard rule to allow "index"\nroute to "member" role, your "login" route will become defacto unauthorized to anyone, unless you add a new rule for\nallowing the route "login" to "member" role.'}),"\n",(0,s.jsx)(n.p,{children:"You can change it in LmcRbacMvc config, as follows:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"use LmcRbacMvc\\Guard\\GuardInterface;\n\nreturn [\n 'lmc_rbac' => [\n 'protection_policy' => GuardInterface::POLICY_DENY\n ]\n];\n"})}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"NOTE: this policy will block ANY route/controller (so it will also block any console routes or controllers). The\ndeny policy is much more secure, but it needs much more configuration to work with."}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"built-in-guards",children:"Built-in guards"}),"\n",(0,s.jsx)(n.p,{children:"LmcRbacMvc comes with four guards, in order of priority :"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"RouteGuard : protect a set of routes based on the identity roles"}),"\n",(0,s.jsx)(n.li,{children:"RoutePermissionsGuard : protect a set of routes based on roles permissions"}),"\n",(0,s.jsx)(n.li,{children:"ControllerGuard : protect a controllers and/or actions based on the identity roles"}),"\n",(0,s.jsx)(n.li,{children:"ControllerPermissionsGuard : protect a controllers and/or actions based on roles permissions"}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["All guards must be added in the ",(0,s.jsx)(n.code,{children:"guards"})," subkey:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n // Guards config here!\n ]\n ]\n];\n"})}),"\n",(0,s.jsx)(n.p,{children:"Because of the way Laminas Framework handles config, you can without problem define some rules in one module, and\nmore rules in another module. All the rules will be automatically merged."}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:'For your mental health, I recommend you to use either the route guard OR the controller guard, but not both. If\nyou decide to use both conjointly, I recommend you to set the protection policy to "allow" (otherwise, you will\nneed to define rules for every routes AND every controller, which can become quite frustrating!).'}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["Please note that if your application uses both route and controller guards, route guards are always executed\n",(0,s.jsx)(n.strong,{children:"before"})," controller guards (they have a higher priority)."]}),"\n",(0,s.jsx)(n.h3,{id:"routeguard",children:"RouteGuard"}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsxs)(n.p,{children:["The RouteGuard listens to the ",(0,s.jsx)(n.code,{children:"MvcEvent::EVENT_ROUTE"})," event with a priority of -5."]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:'The RouteGuard allows your application to protect a route or a hierarchy of routes. You must provide an array of "key" => "value",\nwhere the key is a route pattern and the value is an array of role names:'}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\RouteGuard' => [\n 'admin*' => ['admin'],\n 'login' => ['guest']\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"Only one role in a rule needs to be matched (it is an OR condition)."}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:'Those rules grant access to all admin routes to users that have the "admin" role, and grant access to the "login"\nroute to users that have the "guest" role (eg.: most likely unauthenticated users).'}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"The route pattern is not a regex. It only supports the wildcard (*) character, that replaces any segment."}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"You can also use the wildcard character * for roles:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\RouteGuard' => [\n 'home' => ['*']\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsx)(n.p,{children:'This rule grants access to the "home" route to anyone.'}),"\n",(0,s.jsx)(n.p,{children:"Finally, you can also omit the roles array to completely block a route, for maintenance purpose for example :"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\RouteGuard' => [\n 'route_under_construction'\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsx)(n.p,{children:"This rule will be inaccessible."}),"\n",(0,s.jsx)(n.p,{children:"Note : this last example could be (and should be) written in a more explicit way :"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\RouteGuard' => [\n 'route_under_construction' => []\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsx)(n.h3,{id:"routepermissionsguard",children:"RoutePermissionsGuard"}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsxs)(n.p,{children:["The RoutePermissionsGuard listens to the ",(0,s.jsx)(n.code,{children:"MvcEvent::EVENT_ROUTE"})," event with a priority of -8."]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:'The RoutePermissionsGuard allows your application to protect a route or a hierarchy of routes. You must provide an array of "key" => "value",\nwhere the key is a route pattern and the value is an array of permission names:'}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\RoutePermissionsGuard' => [\n 'admin*' => ['admin'],\n 'post/manage' => ['post.update', 'post.delete']\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"By default, all permissions in a rule must be matched (an AND condition)."}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["In the previous example, one must have ",(0,s.jsx)(n.code,{children:"post.update"})," ",(0,s.jsx)(n.strong,{children:"AND"})," ",(0,s.jsx)(n.code,{children:"post.delete"})," permissions\nto access the ",(0,s.jsx)(n.code,{children:"post/manage"})," route. You can also specify an OR condition like so:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"use LmcRbacMvc\\Guard\\GuardInterface;\n\nreturn [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\RoutePermissionsGuard' => [\n 'post/manage' => [\n 'permissions' => ['post.update', 'post.delete'],\n 'condition' => GuardInterface::CONDITION_OR\n ]\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"Permissions are linked to roles, not to users"}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:'Those rules grant access to all admin routes to roles that have the "admin" permission, and grant access to the\n"post/delete" route to roles that have the "post.delete" or "admin" permissions.'}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"The route pattern is not a regex. It only supports the wildcard (*) character, that replaces any segment."}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"You can also use the wildcard character * for permissions:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\RoutePermissionsGuard' => [\n 'home' => ['*']\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsx)(n.p,{children:'This rule grants access to the "home" route to anyone.'}),"\n",(0,s.jsx)(n.p,{children:"Finally, you can also use an empty array to completly block a route, for maintenance purpose for example :"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\RoutePermissionsGuard' => [\n 'route_under_construction' => []\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsx)(n.p,{children:"This route will be inaccessible."}),"\n",(0,s.jsx)(n.h3,{id:"controllerguard",children:"ControllerGuard"}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsxs)(n.p,{children:["The ControllerGuard listens to the ",(0,s.jsx)(n.code,{children:"MvcEvent::EVENT_ROUTE"})," event with a priority of -10."]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"The ControllerGuard allows your application to protect a controller. You must provide an array of arrays:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\ControllerGuard' => [\n [\n 'controller' => 'MyController',\n 'roles' => ['guest', 'member']\n ]\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"Only one role in a rule need to be matched (it is an OR condition)."}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:'Those rules grant access to each actions of the MyController controller to users that have either the "guest" or\n"member" roles.'}),"\n",(0,s.jsx)(n.p,{children:"As for RouteGuard, you can use a wildcard (*) character for roles."}),"\n",(0,s.jsx)(n.p,{children:"You can also specify optional actions, so that the rule only apply to one or several actions:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\ControllerGuard' => [\n [\n 'controller' => 'MyController',\n 'actions' => ['read', 'edit'],\n 'roles' => ['guest', 'member']\n ]\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsx)(n.p,{children:"You can combine a generic rule and a specific action rule for the same controller, as follows:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\ControllerGuard' => [\n [\n 'controller' => 'PostController',\n 'roles' => ['member']\n ],\n [\n 'controller' => 'PostController',\n 'actions' => ['delete'],\n 'roles' => ['admin']\n ]\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsx)(n.p,{children:'These rules grant access to each controller action to users that have the "member" role, but restrict the\n"delete" action to "admin" only.'}),"\n",(0,s.jsx)(n.h3,{id:"controllerpermissionsguard",children:"ControllerPermissionsGuard"}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsxs)(n.p,{children:["The ControllerPermissionsGuard listens to the ",(0,s.jsx)(n.code,{children:"MvcEvent::EVENT_ROUTE"})," event with a priority of -13."]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"The ControllerPermissionsGuard allows your application to protect a controller using permissions. You must provide an array of arrays:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'LmcRbacMvc\\Guard\\ControllerPermissionsGuard' => [\n [\n 'controller' => 'MyController',\n 'permissions' => ['post.update', 'post.delete']\n ]\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"All permissions in a rule must be matched (it is an AND condition)."}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["In the previous example, the user must have ",(0,s.jsx)(n.code,{children:"post.update"})," ",(0,s.jsx)(n.strong,{children:"AND"})," ",(0,s.jsx)(n.code,{children:"post.delete"})," permissions\nto access each action of the MyController controller."]}),"\n",(0,s.jsx)(n.p,{children:"As for all other guards, you can use a wildcard (*) character for permissions."}),"\n",(0,s.jsx)(n.p,{children:"The configuration rules are the same as for ControllerGuard."}),"\n",(0,s.jsx)(n.h3,{id:"security-notice",children:"Security notice"}),"\n",(0,s.jsxs)(n.p,{children:["RouteGuard and ControllerGuard listen to the ",(0,s.jsx)(n.code,{children:"MvcEvent::EVENT_ROUTE"})," event. Therefore, if you use the\n",(0,s.jsx)(n.code,{children:"forward"})," method in your controller, those guards will not intercept and check requests (because internally\nLaminas MVC does not trigger again a new MVC loop)."]}),"\n",(0,s.jsx)(n.p,{children:"Most of the time, this is not an issue, but you must be aware of it, and this is an additional reason why you\nshould always protect your services too."}),"\n",(0,s.jsx)(n.h2,{id:"creating-custom-guards",children:"Creating custom guards"}),"\n",(0,s.jsx)(n.p,{children:"LmcRbacMvc is flexible enough to allow you to create custom guards. Let's say we want to create a guard that will\nrefuse access based on an IP addresses blacklist."}),"\n",(0,s.jsx)(n.p,{children:"First create the guard:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"namespace Application\\Guard;\n\nuse Laminas\\Http\\Request as HttpRequest;\nuse Laminas\\Mvc\\MvcEvent;\nuse LmcRbacMvc\\Guard\\AbstractGuard;\n\nclass IpGuard extends AbstractGuard\n{\n const EVENT_PRIORITY = 100;\n\n /**\n * List of IPs to blacklist\n */\n protected $ipAddresses = [];\n\n /**\n * @param array $ipAddresses\n */\n public function __construct(array $ipAddresses)\n {\n $this->ipAddresses = $ipAddresses;\n }\n\n /**\n * @param MvcEvent $event\n * @return bool\n */\n public function isGranted(MvcEvent $event)\n {\n $request = $event->getRequest();\n\n if (!$request instanceof HttpRequest) {\n return true;\n }\n\n $clientIp = $_SERVER['REMOTE_ADDR'];\n\n return !in_array($clientIp, $this->ipAddresses);\n }\n}\n"})}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsxs)(n.p,{children:["Guards must implement ",(0,s.jsx)(n.code,{children:"LmcRbacMvc\\Guard\\GuardInterface"}),"."]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["By default, guards are listening to the event ",(0,s.jsx)(n.code,{children:"MvcEvent::EVENT_ROUTE"})," with a priority of -5 (you can change the default\nevent to listen by overriding the ",(0,s.jsx)(n.code,{children:"EVENT_NAME"})," constant in your guard subclass). However, in this case, we don't\neven need to wait for the route to be matched, so we overload the ",(0,s.jsx)(n.code,{children:"EVENT_PRIORITY"})," constant to be executed earlier."]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"isGranted"})," method simply retrieves the client IP address, and checks it against the blacklist."]}),"\n",(0,s.jsx)(n.p,{children:"However, for this to work, we must register the newly created guard with the guard plugin manager. To do so, add the\nfollowing code in your config:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guard_manager' => [\n 'factories' => [\n 'Application\\Guard\\IpGuard' => 'Application\\Factory\\IpGuardFactory'\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"guard_manager"})," config follows a conventional service manager configuration format."]}),"\n",(0,s.jsx)(n.p,{children:"Now, let's create the factory:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"namespace Application\\Factory;\n\nuse Application\\Guard\\IpGuard;\nuse Laminas\\ServiceManager\\Factory\\FactoryInterface;\nuse Laminas\\ServiceManager\\ServiceLocatorInterface;\n\nclass IpGuardFactory implements FactoryInterface\n{\n /**\n * {@inheritDoc}\n */\n public function __invoke(ContainerInterface $container, $requestedName, array $options = null)\n {\n if (null === $options) {\n $options = [];\n }\n return new IpGuard($options);\n }\n}\n"})}),"\n",(0,s.jsx)(n.p,{children:"In a real use case, you would likely fetched the blacklist from a database."}),"\n",(0,s.jsxs)(n.p,{children:["Now we just need to add the guard to the ",(0,s.jsx)(n.code,{children:"guards"})," option, so that LmcRbacMvc can execute the logic behind this guard. In\nyour config, add the following code:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-php",children:"return [\n 'lmc_rbac' => [\n 'guards' => [\n 'Application\\Guard\\IpGuard' => [\n '87.45.66.46',\n '65.87.35.43'\n ]\n ]\n ]\n];\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The array of IP addresses will be passed to ",(0,s.jsx)(n.code,{children:"IpGuardFactory::__invoke"})," in the ",(0,s.jsx)(n.code,{children:"$options"})," parameter."]})]})}function d(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},7376:(e,n,r)=>{r.d(n,{A:()=>s});const s=r.p+"assets/images/workflow-with-guards-9421d2ccbded4218039d3c55d9e07d64.png"},4676:(e,n,r)=>{r.d(n,{A:()=>s});const s="data:image/png;base64,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"},8453:(e,n,r)=>{r.d(n,{R:()=>a,x:()=>l});var s=r(6540);const o={},t=s.createContext(o);function a(e){const n=s.useContext(t);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:a(e.components),s.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.b6597784.js b/assets/js/runtime~main.0f52da0b.js similarity index 98% rename from assets/js/runtime~main.b6597784.js rename to assets/js/runtime~main.0f52da0b.js index bdb8a1a5..e35a9386 100644 --- a/assets/js/runtime~main.b6597784.js +++ b/assets/js/runtime~main.0f52da0b.js @@ -1 +1 @@ -(()=>{"use strict";var e,t,a,r,c,f={},o={};function d(e){var t=o[e];if(void 0!==t)return t.exports;var a=o[e]={id:e,loaded:!1,exports:{}};return f[e].call(a.exports,a,a.exports,d),a.loaded=!0,a.exports}d.m=f,d.c=o,e=[],d.O=(t,a,r,c)=>{if(!a){var f=1/0;for(i=0;i=c)&&Object.keys(d.O).every((e=>d.O[e](a[b])))?a.splice(b--,1):(o=!1,c0&&e[i-1][2]>c;i--)e[i]=e[i-1];e[i]=[a,r,c]},d.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return d.d(t,{a:t}),t},a=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,d.t=function(e,r){if(1&r&&(e=this(e)),8&r)return e;if("object"==typeof e&&e){if(4&r&&e.__esModule)return e;if(16&r&&"function"==typeof e.then)return e}var c=Object.create(null);d.r(c);var f={};t=t||[null,a({}),a([]),a(a)];for(var o=2&r&&e;"object"==typeof o&&!~t.indexOf(o);o=a(o))Object.getOwnPropertyNames(o).forEach((t=>f[t]=()=>e[t]));return f.default=()=>e,d.d(c,f),c},d.d=(e,t)=>{for(var a in t)d.o(t,a)&&!d.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},d.f={},d.e=e=>Promise.all(Object.keys(d.f).reduce(((t,a)=>(d.f[a](e,t),t)),[])),d.u=e=>"assets/js/"+({18:"ee696d42",32:"e7707d54",48:"a94703ab",61:"1f391b9e",98:"a7bd4aaa",107:"4e6224b1",134:"393be207",166:"22465cd7",182:"e252ba15",185:"22d95c7b",209:"01a85c17",223:"8b5d4ccc",246:"f6027d55",249:"ccc49370",280:"51567bd7",317:"9939a46f",390:"b5cb822e",401:"17896441",416:"d9e16301",472:"814f3328",478:"346b82e5",541:"8c0e8602",571:"b9207088",581:"935f2afb",619:"b257daf3",634:"c4f5d8e4",639:"378f56c0",643:"a6aa9e1f",647:"5e95c892",698:"5b72c13b",711:"9e4087bc",770:"02def4a7",781:"e9f64022",803:"3b8c55ea",804:"809dac3e",813:"6875c492",814:"72e14192",894:"2a93c9ee",976:"0e384e19"}[e]||e)+"."+{18:"9027bc46",32:"ffdb8a6c",48:"8b0ccadb",61:"a27a432b",98:"fd305e17",107:"bc2be1c9",134:"d0efb02e",166:"ac6c222b",182:"a3bf887f",185:"eac7701f",209:"8dd5da0a",223:"f7b8e814",237:"7663bed8",246:"533f68e1",249:"c41daa2c",280:"f4194958",317:"a0fe414a",390:"a2615daa",401:"ab15fc7f",416:"fc5858cc",472:"e5c2350a",478:"8532d5c1",533:"11304ac5",541:"e02436f5",571:"6e46699a",581:"d81adf37",619:"75e8f67a",634:"00ce20a8",639:"cc46ce65",643:"aac55eda",647:"1dd55255",698:"e8b2bfc0",711:"bddafc5d",747:"847fa25b",770:"53c9a7f1",781:"07084ef5",803:"95d69cb0",804:"54686ba5",813:"f1af0c91",814:"9f829351",894:"8ca11c62",976:"f67a654a"}[e]+".js",d.miniCssF=e=>{},d.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),d.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r={},c="docs:",d.l=(e,t,a,f)=>{if(r[e])r[e].push(t);else{var o,b;if(void 0!==a)for(var n=document.getElementsByTagName("script"),i=0;i{o.onerror=o.onload=null,clearTimeout(s);var c=r[e];if(delete r[e],o.parentNode&&o.parentNode.removeChild(o),c&&c.forEach((e=>e(a))),t)return t(a)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:o}),12e4);o.onerror=l.bind(null,o.onerror),o.onload=l.bind(null,o.onload),b&&document.head.appendChild(o)}},d.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},d.p="/LmcRbacMvc/",d.gca=function(e){return e={17896441:"401",ee696d42:"18",e7707d54:"32",a94703ab:"48","1f391b9e":"61",a7bd4aaa:"98","4e6224b1":"107","393be207":"134","22465cd7":"166",e252ba15:"182","22d95c7b":"185","01a85c17":"209","8b5d4ccc":"223",f6027d55:"246",ccc49370:"249","51567bd7":"280","9939a46f":"317",b5cb822e:"390",d9e16301:"416","814f3328":"472","346b82e5":"478","8c0e8602":"541",b9207088:"571","935f2afb":"581",b257daf3:"619",c4f5d8e4:"634","378f56c0":"639",a6aa9e1f:"643","5e95c892":"647","5b72c13b":"698","9e4087bc":"711","02def4a7":"770",e9f64022:"781","3b8c55ea":"803","809dac3e":"804","6875c492":"813","72e14192":"814","2a93c9ee":"894","0e384e19":"976"}[e]||e,d.p+d.u(e)},(()=>{var e={354:0,869:0};d.f.j=(t,a)=>{var r=d.o(e,t)?e[t]:void 0;if(0!==r)if(r)a.push(r[2]);else if(/^(354|869)$/.test(t))e[t]=0;else{var c=new Promise(((a,c)=>r=e[t]=[a,c]));a.push(r[2]=c);var f=d.p+d.u(t),o=new Error;d.l(f,(a=>{if(d.o(e,t)&&(0!==(r=e[t])&&(e[t]=void 0),r)){var c=a&&("load"===a.type?"missing":a.type),f=a&&a.target&&a.target.src;o.message="Loading chunk "+t+" failed.\n("+c+": "+f+")",o.name="ChunkLoadError",o.type=c,o.request=f,r[1](o)}}),"chunk-"+t,t)}},d.O.j=t=>0===e[t];var t=(t,a)=>{var r,c,f=a[0],o=a[1],b=a[2],n=0;if(f.some((t=>0!==e[t]))){for(r in o)d.o(o,r)&&(d.m[r]=o[r]);if(b)var i=b(d)}for(t&&t(a);n{"use strict";var e,t,a,r,c,f={},o={};function d(e){var t=o[e];if(void 0!==t)return t.exports;var a=o[e]={id:e,loaded:!1,exports:{}};return f[e].call(a.exports,a,a.exports,d),a.loaded=!0,a.exports}d.m=f,d.c=o,e=[],d.O=(t,a,r,c)=>{if(!a){var f=1/0;for(i=0;i=c)&&Object.keys(d.O).every((e=>d.O[e](a[b])))?a.splice(b--,1):(o=!1,c0&&e[i-1][2]>c;i--)e[i]=e[i-1];e[i]=[a,r,c]},d.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return d.d(t,{a:t}),t},a=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,d.t=function(e,r){if(1&r&&(e=this(e)),8&r)return e;if("object"==typeof e&&e){if(4&r&&e.__esModule)return e;if(16&r&&"function"==typeof e.then)return e}var c=Object.create(null);d.r(c);var f={};t=t||[null,a({}),a([]),a(a)];for(var o=2&r&&e;"object"==typeof o&&!~t.indexOf(o);o=a(o))Object.getOwnPropertyNames(o).forEach((t=>f[t]=()=>e[t]));return f.default=()=>e,d.d(c,f),c},d.d=(e,t)=>{for(var a in t)d.o(t,a)&&!d.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},d.f={},d.e=e=>Promise.all(Object.keys(d.f).reduce(((t,a)=>(d.f[a](e,t),t)),[])),d.u=e=>"assets/js/"+({18:"ee696d42",32:"e7707d54",48:"a94703ab",61:"1f391b9e",98:"a7bd4aaa",107:"4e6224b1",134:"393be207",166:"22465cd7",182:"e252ba15",185:"22d95c7b",209:"01a85c17",223:"8b5d4ccc",246:"f6027d55",249:"ccc49370",280:"51567bd7",317:"9939a46f",390:"b5cb822e",401:"17896441",416:"d9e16301",472:"814f3328",478:"346b82e5",541:"8c0e8602",571:"b9207088",581:"935f2afb",619:"b257daf3",634:"c4f5d8e4",639:"378f56c0",643:"a6aa9e1f",647:"5e95c892",698:"5b72c13b",711:"9e4087bc",770:"02def4a7",781:"e9f64022",803:"3b8c55ea",804:"809dac3e",813:"6875c492",814:"72e14192",894:"2a93c9ee",976:"0e384e19"}[e]||e)+"."+{18:"9027bc46",32:"ffdb8a6c",48:"8b0ccadb",61:"a27a432b",98:"fd305e17",107:"bc2be1c9",134:"d0efb02e",166:"ac6c222b",182:"a3bf887f",185:"eac7701f",209:"8dd5da0a",223:"972489eb",237:"7663bed8",246:"533f68e1",249:"c41daa2c",280:"f4194958",317:"a0fe414a",390:"a2615daa",401:"ab15fc7f",416:"fc5858cc",472:"e5c2350a",478:"8532d5c1",533:"11304ac5",541:"e02436f5",571:"6e46699a",581:"d81adf37",619:"75e8f67a",634:"00ce20a8",639:"cc46ce65",643:"aac55eda",647:"1dd55255",698:"e8b2bfc0",711:"bddafc5d",747:"847fa25b",770:"53c9a7f1",781:"07084ef5",803:"95d69cb0",804:"54686ba5",813:"f1af0c91",814:"9f829351",894:"8ca11c62",976:"f67a654a"}[e]+".js",d.miniCssF=e=>{},d.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),d.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r={},c="docs:",d.l=(e,t,a,f)=>{if(r[e])r[e].push(t);else{var o,b;if(void 0!==a)for(var n=document.getElementsByTagName("script"),i=0;i{o.onerror=o.onload=null,clearTimeout(s);var c=r[e];if(delete r[e],o.parentNode&&o.parentNode.removeChild(o),c&&c.forEach((e=>e(a))),t)return t(a)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:o}),12e4);o.onerror=l.bind(null,o.onerror),o.onload=l.bind(null,o.onload),b&&document.head.appendChild(o)}},d.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},d.p="/LmcRbacMvc/",d.gca=function(e){return e={17896441:"401",ee696d42:"18",e7707d54:"32",a94703ab:"48","1f391b9e":"61",a7bd4aaa:"98","4e6224b1":"107","393be207":"134","22465cd7":"166",e252ba15:"182","22d95c7b":"185","01a85c17":"209","8b5d4ccc":"223",f6027d55:"246",ccc49370:"249","51567bd7":"280","9939a46f":"317",b5cb822e:"390",d9e16301:"416","814f3328":"472","346b82e5":"478","8c0e8602":"541",b9207088:"571","935f2afb":"581",b257daf3:"619",c4f5d8e4:"634","378f56c0":"639",a6aa9e1f:"643","5e95c892":"647","5b72c13b":"698","9e4087bc":"711","02def4a7":"770",e9f64022:"781","3b8c55ea":"803","809dac3e":"804","6875c492":"813","72e14192":"814","2a93c9ee":"894","0e384e19":"976"}[e]||e,d.p+d.u(e)},(()=>{var e={354:0,869:0};d.f.j=(t,a)=>{var r=d.o(e,t)?e[t]:void 0;if(0!==r)if(r)a.push(r[2]);else if(/^(354|869)$/.test(t))e[t]=0;else{var c=new Promise(((a,c)=>r=e[t]=[a,c]));a.push(r[2]=c);var f=d.p+d.u(t),o=new Error;d.l(f,(a=>{if(d.o(e,t)&&(0!==(r=e[t])&&(e[t]=void 0),r)){var c=a&&("load"===a.type?"missing":a.type),f=a&&a.target&&a.target.src;o.message="Loading chunk "+t+" failed.\n("+c+": "+f+")",o.name="ChunkLoadError",o.type=c,o.request=f,r[1](o)}}),"chunk-"+t,t)}},d.O.j=t=>0===e[t];var t=(t,a)=>{var r,c,f=a[0],o=a[1],b=a[2],n=0;if(f.some((t=>0!==e[t]))){for(r in o)d.o(o,r)&&(d.m[r]=o[r]);if(b)var i=b(d)}for(t&&t(a);n Blog | LmcRbacMvc - + diff --git a/blog/archive.html b/blog/archive.html index 3a85527c..15d3ef74 100644 --- a/blog/archive.html +++ b/blog/archive.html @@ -5,7 +5,7 @@ Archive | LmcRbacMvc - + diff --git a/blog/new-documentation.html b/blog/new-documentation.html index e9681624..c59e6d7d 100644 --- a/blog/new-documentation.html +++ b/blog/new-documentation.html @@ -5,7 +5,7 @@ New documentation | LmcRbacMvc - + diff --git a/blog/tags.html b/blog/tags.html index 8d911ea4..cc27cef9 100644 --- a/blog/tags.html +++ b/blog/tags.html @@ -5,7 +5,7 @@ Tags | LmcRbacMvc - + diff --git a/blog/tags/laminas.html b/blog/tags/laminas.html index fbd6c15e..988c1bfe 100644 --- a/blog/tags/laminas.html +++ b/blog/tags/laminas.html @@ -5,7 +5,7 @@ 2 posts tagged with "laminas" | LmcRbacMvc - + diff --git a/blog/tags/lmcrbacmvc.html b/blog/tags/lmcrbacmvc.html index 2c9d1096..9c17ae39 100644 --- a/blog/tags/lmcrbacmvc.html +++ b/blog/tags/lmcrbacmvc.html @@ -5,7 +5,7 @@ One post tagged with "lmcrbacmvc" | LmcRbacMvc - + diff --git a/blog/tags/php.html b/blog/tags/php.html index 68f6646c..dec489ef 100644 --- a/blog/tags/php.html +++ b/blog/tags/php.html @@ -5,7 +5,7 @@ 2 posts tagged with "PHP" | LmcRbacMvc - + diff --git a/blog/welcome.html b/blog/welcome.html index 636858cf..6fbee8f9 100644 --- a/blog/welcome.html +++ b/blog/welcome.html @@ -5,7 +5,7 @@ Welcome | LmcRbacMvc - + diff --git a/docs/cookbook.html b/docs/cookbook.html index 05ffc3a5..ba8f7de1 100644 --- a/docs/cookbook.html +++ b/docs/cookbook.html @@ -5,7 +5,7 @@ Cookbook | LmcRbacMvc - + diff --git a/docs/guards.html b/docs/guards.html index f591b7f4..8744d208 100644 --- a/docs/guards.html +++ b/docs/guards.html @@ -5,7 +5,7 @@ Guards | LmcRbacMvc - + @@ -167,7 +167,7 @@

Creat

The isGranted method simply retrieves the client IP address, and checks it against the blacklist.

However, for this to work, we must register the newly created guard with the guard plugin manager. To do so, add the following code in your config:

-
return [
'zfc_rbac' => [
'guard_manager' => [
'factories' => [
'Application\Guard\IpGuard' => 'Application\Factory\IpGuardFactory'
]
]
]
];
+
return [
'lmc_rbac' => [
'guard_manager' => [
'factories' => [
'Application\Guard\IpGuard' => 'Application\Factory\IpGuardFactory'
]
]
]
];

The guard_manager config follows a conventional service manager configuration format.

Now, let's create the factory:

namespace Application\Factory;

use Application\Guard\IpGuard;
use Laminas\ServiceManager\Factory\FactoryInterface;
use Laminas\ServiceManager\ServiceLocatorInterface;

class IpGuardFactory implements FactoryInterface
{
/**
* {@inheritDoc}
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
if (null === $options) {
$options = [];
}
return new IpGuard($options);
}
}
diff --git a/docs/installation.html b/docs/installation.html index 13f04fa5..5c83123b 100644 --- a/docs/installation.html +++ b/docs/installation.html @@ -5,7 +5,7 @@ Requirements and Installation | LmcRbacMvc - + diff --git a/docs/intro.html b/docs/intro.html index d709fbbd..96e891a6 100644 --- a/docs/intro.html +++ b/docs/intro.html @@ -5,7 +5,7 @@ Introduction | LmcRbacMvc - + diff --git a/docs/quick-start.html b/docs/quick-start.html index 0a265562..75cd646b 100644 --- a/docs/quick-start.html +++ b/docs/quick-start.html @@ -5,7 +5,7 @@ Quick Start | LmcRbacMvc - + diff --git a/docs/role-providers.html b/docs/role-providers.html index c0eb354e..05142797 100644 --- a/docs/role-providers.html +++ b/docs/role-providers.html @@ -5,7 +5,7 @@ Role providers | LmcRbacMvc - + diff --git a/docs/strategies.html b/docs/strategies.html index e2c450a8..dff12357 100644 --- a/docs/strategies.html +++ b/docs/strategies.html @@ -5,7 +5,7 @@ Strategies | LmcRbacMvc - + diff --git a/docs/support.html b/docs/support.html index 2edfde75..33d7c3bb 100644 --- a/docs/support.html +++ b/docs/support.html @@ -5,7 +5,7 @@ Support | LmcRbacMvc - + diff --git a/docs/using-the-authorization-service.html b/docs/using-the-authorization-service.html index cd0d362a..5748b8f7 100644 --- a/docs/using-the-authorization-service.html +++ b/docs/using-the-authorization-service.html @@ -5,7 +5,7 @@ Using the Authorization Service | LmcRbacMvc - + diff --git a/index.html b/index.html index d3914c84..7768376c 100644 --- a/index.html +++ b/index.html @@ -5,7 +5,7 @@ Hello from LmcRbacMvc | LmcRbacMvc - + diff --git a/markdown-page.html b/markdown-page.html index 833b4a0b..4fbfb53d 100644 --- a/markdown-page.html +++ b/markdown-page.html @@ -5,7 +5,7 @@ Markdown page example | LmcRbacMvc - +