Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yii2
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
PSDI Army
yii2
Commits
a3632dbb
Commit
a3632dbb
authored
Apr 16, 2014
by
Qiang Xue
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fixes #3129: added RBAC documentation.
parent
66842a48
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
343 additions
and
25 deletions
+343
-25
authorization.md
docs/guide/authorization.md
+343
-25
No files found.
docs/guide/authorization.md
View file @
a3632dbb
Authorization
=============
Authorization is the process of verifying that
user has enough permissions to do something. Yii provides several methods
of controlling it
.
Authorization is the process of verifying that
a user has enough permission to do something. Yii provides two authorization
methods: Access Control Filter (ACF) and Role-Based Access Control (RBAC)
.
Access control basics
Access Control Filter
---------------------
Basic access control is very simple to implement using
[
[yii\filters\AccessControl
]
]:
Access Control Filter (ACF) is a simple authorization method that is best used by applications that only need some
simple access control. As its name indicates, ACF is an action filter that can be attached to a controller or a module
as a behavior. ACF will check a set of
[
[yii\filters\AccessControl::rules|access rules
]
] to make sure the current user
can access the requested action.
The code below shows how to use ACF which is implemented as
[
[yii\filters\AccessControl
]
]:
```
php
use
yii\filters\AccessControl
;
class
SiteController
extends
Controller
{
public
function
behaviors
()
{
return
[
'access'
=>
[
'class'
=>
\yii\filters\
AccessControl
::
className
(),
'class'
=>
AccessControl
::
className
(),
'only'
=>
[
'login'
,
'logout'
,
'signup'
],
'rules'
=>
[
[
'actions'
=>
[
'login'
,
'signup'
],
'allow'
=>
true
,
'actions'
=>
[
'login'
,
'signup'
],
'roles'
=>
[
'?'
],
],
[
'actions'
=>
[
'logout'
],
'allow'
=>
true
,
'actions'
=>
[
'logout'
],
'roles'
=>
[
'@'
],
],
],
...
...
@@ -34,29 +42,85 @@ class SiteController extends Controller
];
}
// ...
}
```
In the code above ACF is attached to the
`site`
controller as a behavior. This is the typical way of using an action
filter. The
`only`
option specifies that the ACF should only be applied to
`login`
,
`logout`
and
`signup`
actions.
The
`rules`
option specifies the
[
[yii\filters\AccessRule|access rules
]
], which reads as follows:
-
Allow all guest (not yet authenticated) users to access 'login' and 'signup' actions. The
`roles`
option
contains a question mark
`?`
which is a special token recognized as "guests".
-
Allow authenticated users to access 'logout' action. The
`@`
character is another special token recognized as
authenticated users.
When ACF performs authorization check, it will examine the rules one by one from top to bottom until it finds
a match. The
`allow`
value of the matching rule will then be used to judge if the user is authorized. If none
of the rules matches, it means the user is NOT authorized and ACF will stop further action execution.
By default, ACF does only of the followings when it determines a user is not authorized to access the current action:
*
If the user is a guest, it will call
[
[yii\web\User::loginRequired()
]
], which may redirect the browser to the login page.
*
If the user is already authenticated, it will throw a
[
[yii\web\ForbiddenHttpException
]
].
You may customize this behavior by configuring the
[
[yii\filters\AccessControl::denyCallback
]
] property:
```
php
[
'class'
=>
AccessControl
::
className
(),
'denyCallback'
=>
function
(
$rule
,
$action
)
{
throw
new
\Exception
(
'You are not allowed to access this page'
);
}
]
```
In the code above we're attaching access control behavior to a controller. Since there's
`only`
option specified, it
will be applied to 'login', 'logout' and 'signup' actions only. A set of rules that are basically options for
[
[yii\filters\AccessRule
]
] reads as follows:
[
[yii\filters\AccessRule|Access rules
]
] support many options. Below is a summary of the supported options.
You may also extend
[
[yii\filters\AccessRule
]
] to create your own customized access rule classes.
*
[
[yii\filters\AccessRule::allow|allow
]
]: specifies whether this is an "allow" or "deny" rule.
*
[
[yii\filters\AccessRule::actions|actions
]
]: specifies which actions this rule matches. This should
be an array of action IDs. The comparison is case-sensitive. If this option is empty or not set,
it means the rule applies to all actions.
*
[
[yii\filters\AccessRule::controllers|controllers
]
]: specifies which controllers this rule
matches. This should be an array of controller IDs. The comparison is case-sensitive. If this option is
empty or not set, it means the rule applies to all controllers.
-
Allow all guest (not yet authenticated) users to access 'login' and 'signup' actions.
-
Allow authenticated users to access 'logout' action.
*
[
[yii\filters\AccessRule::roles|roles
]
]: specifies which user roles that this rule matches.
Two special roles are recognized, and they are checked via
[
[yii\web\User::isGuest
]
]:
-
`?`
: matches a guest user (not authenticated yet)
-
`@`
: matches an authenticated user
Using other role names requires RBAC (to be described in the next section), and
[
[yii\web\User::can()
]
] will be called.
If this option is empty or not set, it means this rule applies to all roles.
Rules are checked one by one from top to bottom. If rule matches, action takes place immediately. If not, next rule is
checked. If no rules matched access is denied.
*
[
[yii\filters\AccessRule::ips|ips
]
]: specifies which
[
[yii\web\Request::Request::userIP|client IP addresses
]
] this rule matches.
An IP address can contain the wildcard
`*`
at the end so that it matches IP addresses with the same prefix.
For example, '192.168.
*
' matches all IP addresses in the segment '192.168.'. If this option is empty or not set,
it means this rule applies to all IP addresses.
[
[yii\filters\AccessRule
]
] is quite flexible and allows additionally to what was demonstrated checking IPs and request method
(i.e. POST, GET). If it's not enough you can specify your own check via anonymous function:
*
[
[yii\filters\AccessRule::verbs|verbs
]
]: specifies which request method (e.g.
`GET`
,
`POST`
) this rule matches.
The comparison is case-insensitive.
*
[
[yii\filters\AccessRule::matchCallback|matchCallback
]
]: specifies a PHP callable that should be called to determine
if this rule should be applied.
*
[
[yii\filters\AccessRule::denyCallback|denyCallback
]
]: specifies a PHP callable that should be called when this rule
will deny the access.
Below is an example showing how to make use of the
`matchCallback`
option, which allows you to write arbitrary access
check logic:
```
php
use
yii\filters\AccessControl
;
class
SiteController
extends
Controller
{
public
function
behaviors
()
{
return
[
'access'
=>
[
'class'
=>
\yii\filters\
AccessControl
::
className
(),
'class'
=>
AccessControl
::
className
(),
'only'
=>
[
'special-callback'
],
'rules'
=>
[
[
...
...
@@ -66,23 +130,277 @@ class SiteController extends Controller
return
date
(
'd-m'
)
===
'31-10'
;
}
],
```
And the action:
],
],
];
}
```
php
// ...
// Match callback called! This page can be accessed only each October 31st
public
function
actionSpecialCallback
()
{
return
$this
->
render
(
'happy-halloween'
);
}
}
```
Sometimes you want a custom action to be taken when access is denied. In this case you can specify
`denyCallback`
.
Role based access control (RBAC)
--------------------------------
Role based access control is very flexible approach to controlling access that is a perfect match for complex systems
where permissions are customizable.
Role-Based Access Control (RBAC) provides a simple yet powerful centralized access control. Please refer to
the
[
Wiki article
](
http://en.wikipedia.org/wiki/Role-based_access_control
)
for details about comparing RBAC
with other more traditional access control schemes.
Yii implements a General Hierarchical RBAC, following the
[
NIST RBAC model
](
http://csrc.nist.gov/rbac/sandhu-ferraiolo-kuhn-00.pdf
)
.
It provides the RBAC functionality through the
[
[yii\rbac\ManagerInterface|authManager
]
] application component.
Using RBAC involves two parts of work. The first part is to build up the RBAC authorization data, and the second
part is to use the authorization data to perform access check in places where it is needed.
To facilitate our description next, we will first introduce some basic RBAC concepts.
### Basic Concepts
A role represents a collection of
*permissions*
(e.g. viewing reports, creating reports). A role may be assigned
to one or multiple users. To check if a user has a specified permission, we may check if the user is assigned
with a role that contains that permission.
Associated with each role or permission, there may be a
*rule*
. A rule represents a piece of code that will be
executed during access check to determine if the corresponding role or permission applies to the current user.
For example, the "update report" permission may have a rule that checks if the current user is the report creator.
During access checking, if the user is NOT the report creator, he/she will be considered not having the "update report" permission.
Both roles and permissions can be organized in a hierarchy. In particular, a role may consist of other roles or permissions;
and a permission may consist of other permissions. Yii implements a
*partial order*
hierarchy which includes the
more special
*tree*
hierarchy. While a role can contain a permission, it is not true vice versa.
### Configuring RBAC Manager
Before we set off to define authorization data and perform access checking, we need to configure the
[
[yii\base\Application::authManager|authManager
]
] application component. Yii provides two types of authorization managers:
[
[yii\rbac\PhpManager
]
] and
[
[yii\rbac\DbManager
]
]. The former uses a PHP script file to store authorization
data, while the latter stores authorization data in database. You may consider using the former if your application
does not require very dynamic role and permission management.
The following code shows how to configure
`authManager`
in the application configuration:
```
php
return
[
// ...
'components'
=>
[
'authManager'
=>
[
'class'
=>
'yii\rbac\PhpManager'
,
],
// ...
],
];
```
The
`authManager`
can now be accessed via
`\Yii::$app->authManager`
.
### Building Authorization Data
Building authorization data is all about the following kinds of work:
*
defining roles and permissions;
*
establishing relations among roles and permissions;
*
defining rules;
*
associating rules with roles and permissions;
*
assigning roles to users.
The work can be done once for all via a console command for applications that require very simple RBAC.
It may also need a set of user interfaces to allow applications with complex RBAC needs to continuously
updating the authorization data.
The example below shows how to use
`authManager`
to build authorization data:
```
php
$auth
=
Yii
::
$app
->
authManager
;
// add "createPost" permission
$createPost
=
$auth
->
createPermission
(
'createPost'
);
$createPost
->
description
=
'create a post'
;
$auth
->
add
(
$createPost
);
// add "readPost" permission
$readPost
=
$auth
->
createPermission
(
'readPost'
);
$readPost
->
description
=
'read a post'
;
$auth
->
add
(
$readPost
);
// add "updatePost" permission
$updatePost
=
$auth
->
createPermission
(
'updatePost'
);
$updatePost
->
description
=
'update post'
;
$auth
->
add
(
$updatePost
);
// add "reader" role and give this role the "readPost" permission
$reader
=
$auth
->
createRole
(
'reader'
);
$auth
->
add
(
$reader
);
$auth
->
addChild
(
$reader
,
$readPost
);
// add "author" role and give this role the "createPost" permission
// as well as the permissions of the "reader" role
$author
=
$auth
->
createRole
(
'author'
);
$auth
->
add
(
$author
);
$auth
->
addChild
(
$author
,
$createPost
);
$auth
->
addChild
(
$author
,
$reader
);
// add "admin" role and give this role the "updatePost" permission
// as well as the permissions of the "author" role
$admin
=
$auth
->
createRole
(
'admin'
);
$auth
->
add
(
$admin
);
$auth
->
addChild
(
$admin
,
$updatePost
);
$auth
->
addChild
(
$admin
,
$author
);
// assign roles to users
$auth
->
assign
(
$reader
,
'reader A'
);
$auth
->
assign
(
$author
,
'author B'
);
$auth
->
assign
(
$admin
,
'admin C'
);
```
> Tip: By default, [[yii\rbac\PhpManager]] stores RBAC data in the file `@app/data/rbac.php`.
Sometimes when you want to make some minor changes to the RBAC data, you may directly edit this file.
### Using Rules
As aforementioned, rules add additional constraint to roles and permissions. A rule is a class extending
from
[
[yii\rbac\Rule
]
]. It must implement the
[
[yii\rbac\Rule::execute()|execute()
]
] method. Below is
an example:
```
php
namespace
app\rbac
;
use
yii\rbac\Rule
;
/**
* Checks if authorID matches user passed via params
*/
class
AuthorRule
extends
Rule
{
public
$name
=
'isAuthor'
;
/**
* @param string|integer $user the user ID.
* @param Item $item the role or permission that this rule is associated with
* @param array $params parameters passed to ManagerInterface::checkAccess().
* @return boolean a value indicating whether the rule permits the role or permission it is associated with.
*/
public
function
execute
(
$user
,
$item
,
$params
)
{
return
isset
(
$params
[
'post'
])
?
$params
[
'post'
]
->
createdBy
==
$user
:
false
;
}
}
```
The rule above checks if the
`post`
is created by
`$user`
. It can be used in the following
to create a special permission
`updateOwnPost`
:
```
php
// add the rule
$rule
=
new
\app\rbac\AuthorRule
;
$auth
->
add
(
$rule
);
// add the "updateOwnPost" permission and associate the rule with it.
$updateOwnPost
=
$this
->
auth
->
createPermission
(
'updateOwnPost'
);
$updateOwnPost
->
description
=
'update own post'
;
$updateOwnPost
->
ruleName
=
$rule
->
name
;
$auth
->
add
(
$updateOwnPost
);
// allow "author" to update their own posts
$auth
->
addChild
(
$author
,
$updateOwnPost
);
```
### Access Check
With the authorization data ready, access check is as simple as a call to the
[
[yii\rbac\ManagerInterface::checkAccess()
]
]
method. Because most access check is about the current user, for convenience Yii provides a shortcut method
[
[yii\web\User::can()
]
], which can be used like the following:
```
php
if
(
\Yii
::
$app
->
user
->
can
(
'createPost'
))
{
// create post
}
```
To check the
`updateOwnPost`
permission, an extra parameter is required by the
`AuthorRule`
described before.
```
php
if
(
\Yii
::
$app
->
user
->
can
(
'updatePost'
,
[
'post'
=>
$post
]))
{
// update post
}
```
### Using Default Roles
A default role is a role that is
*implicitly*
assigned to
*all*
users. The call to
[
[yii\rbac\ManagerInterface::assign()
]
]
is not needed, and the authorization data does not contain its assignment information.
A default role is usually associated with a rule which determines if the role applies to the user being checked.
Default roles are often used in applications which already have some sort of role assignment. For example, an application
may have a "group" column in its user table to represent which privilege group each user belongs to.
If each privilege group can be mapped to a RBAC role, you can use the default role feature to automatically
assign each user to a RBAC role. Let's use an example to show how this can be done.
Assume in the user table, you have a
`group`
column which uses 1 to represent the administrator group and 2 the author group.
You plan to have two RBAC roles
`admin`
and
`author`
to represent the permissions for these two groups, respectively.
You can create set up the RBAC data as follows,
```php
namespace app\rbac;
use yii\rbac\Rule;
/**
* Checks if authorID matches user passed via params
*/
class UserGroupRule extends Rule
{
public $name = 'userGroup';
public function execute($user, $item, $params)
{
$group = \Yii::$app->user->identity->group;
return $group == 1 && $item->name === 'admin' || $group == 2 && $item->name === 'author';
}
}
$rule = new \app\rbac\UserGroupRule;
$auth->add($rule);
$admin = $auth->createRole('admin');
$admin->ruleName = $rule->name;
$auth->add($admin);
// ... add permissions as children of $admin ...
$author = $auth->createRole('author');
$author->ruleName = $rule->name;
$auth->add($author);
// ... add permissions as children of $author ...
```
Next, configure
`authManager`
by listing the two roles in
[
[yii\rbac\ManagerInterface::defaultRoles
]
]:
```
php
return
[
// ...
'components'
=>
[
'authManager'
=>
[
'class'
=>
'yii\rbac\PhpManager'
,
'defaultRoles'
=>
[
'admin'
,
'author'
],
],
// ...
],
];
```
Now if you perform an access check, both of the
`admin`
and
`author`
roles will be checked by evaluating
the rules associated with them. If the rule returns true, it means the role applies to the current user.
Based on the above rule implementation, this means if the
`group`
value of a user is 1, the
`admin`
role
would apply to the user; and if the
`group`
value is 2, the
`author`
role would apply.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment