关于用户权限,有几种不同的处理方法,如位运算和ACL,他们都各有千秋。
使用位运算控制权限,由于在计算机中只允许位移次数在32或64次之间,所有权限最多只能有32-64位。
位运算控制权限资料链接:链接1,备用链接
http://xiaobin.net/200906/bitwise-permission/
http://www.cnblogs.com/toby/archive/2011/10/23/2221863.html
使用访问控制列表(ACL:access control list),但是这种方法只允许向对象分配权限,而无法使对象进行一些特殊的操作。
本文讲述的是“基于角色的访问控制”(RBAC:role based access control)。
用户通过赋予不同的角色来得到相关的权限,不同的角色又可以分配不同的权限。因此权限分配非常灵活。
但是缺点是,如果没有很好的对权限和角色进行组织,那么系统将会变得非常混乱。
RBAC的实现过程
数据库设计,RBAC的实现过程需要5张表:角色表、权限表、角色权限关联表、用户角色关联表、用户表。
其中用户表根据自己的项目进行设定,本文中不提供设计数据库的sql语句了,只使用到用户表中的位移id(user_id)。
几个表内容如下:
roles(角色) 存储role id, role name
permissions(权限) 存储permission id, description
role_perm 存储角色和权限的关联表role_id, perm_id
user_role 存储用户和角色的关联表user_id, role_id
下面是建表SQL语句:
02 | role_id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, |
03 | role_name VARCHAR(50) NOT NULL, |
07 | CREATE TABLE permissions ( |
08 | perm_id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, |
09 | perm_name VARCHAR(50) NOT NULL, |
13 | CREATE TABLE role_perm ( |
14 | role_id INTEGER UNSIGNED NOT NULL, |
15 | perm_id INTEGER UNSIGNED NOT NULL, |
16 | FOREIGN KEY (role_id) REFERENCES roles(role_id), |
17 | FOREIGN KEY (perm_id) REFERENCES permissions(perm_id) |
20 | CREATE TABLE user_role ( |
21 | user_id INTEGER UNSIGNED NOT NULL, |
22 | role_id INTEGER UNSIGNED NOT NULL, |
23 | FOREIGN KEY (user_id) REFERENCES users(user_id), |
24 | FOREIGN KEY (role_id) REFERENCES roles(role_id) |
默认情况下我们不需要对用户表中的用户进行角色分配,根据你自己的项目,写个sql来给用户进行添加角色,或者在privilegedUser类中对用户初始化一个空权限的角色。
Role Class – [Role.php]
Role是一个返回赋予了相关权限的角色类。并可以检测相关权限的可用状态。
02 | protected $permission; |
04 | protected function __construct(){ |
05 | $this->permission = array(); |
09 | public static function getRolePerms($role_id){ |
11 | $sql = "SELECT t2.perm_name FROM role_perm as t1 |
12 | JOIN permisssions as t2 ON t1.perm_id = t2.perm_id |
13 | WHERE t1.role_id = :role_id"; |
14 | $sth = $GLOBALS['DB']->prepare($sql); |
15 | $sth->execute(array(":role_id" => $role_id)); |
16 | while($row = $sth->fetch(PDO::FETCH_ASSOC)){ |
17 | $role->permission[$row["perm_name"]] = TRUE; |
23 | public function hasPerm($permission){ |
24 | return isset($this->permission[$permission]); |
Privilege User Class
这个可以集成你的User类,在新的方法中为user对象赋予新的属性。
方法initRoles()获取角色,并得到相关权限。
privilegedUser.php
01 | class PrivilegedUser extends User{ |
04 | public function __construct(){ |
05 | parent::__construct(); |
08 | public static function getByUsername($username){ |
09 | $sql = "SELECT * FROM users WHERE username = :username"; |
10 | $sth = $GLOBALS['DB']->prepare($sql); |
11 | $sth->execute(array(":username" => $username)); |
12 | $result = $sth->fetchAll(); |
15 | $privUser = new PrivilegedUser(); |
16 | $privUser->user_id = $result[0]["user_id"]; |
17 | $privUser->username = $username; |
18 | $privUser->password = $result[0]["password"]; |
19 | $privUser->email = $result[0]["email"]; |
20 | $privUser->initRoles(); |
28 | protected function initRoles(){ |
29 | $this->roles = array(); |
30 | $sql = "SELECT t1.role_id, t2.role_name FROM user_role AS t1 |
31 | JOIN roles AS t2 ON t1.role_id = t2.role_id |
32 | WHERE t1.user_id = :user_id"; |
33 | $sth = $GLOBALS["DB"]->prepare($sql); |
34 | $sth->execute(array(":user_id" => $this->user_id)); |
36 | while($row = $sth->fetch(PDO::FETCH_ASSOC)){ |
37 | $this->roles[$row['role_name']] = Role::getRolePerms($row["role_id"]); |
42 | public function hasPrivilege($perm){ |
43 | foreach($this->row as $row){ |
44 | if($role->hasperm($perm)){ |
简单的使用代码:
01 | include_once('User.php'); |
02 | include_once('Role.php'); |
03 | include_once('PrivilegedUser.php'); |
05 | $GLOBALS['DB'] = new PDO('mysql:host=localhost;dbname=dbname', 'root', ''); |
09 | if(isset($_SESSION['loggedin'])){ |
11 | $u = PrivilegedUser::getByUsername('lijing'); |
15 | if($u->hasPrivilege('primission')){ |
代码增强:
以下代码主要为了更好的管理角色权限。将这些方法根据需求放入自己的项目(Role.php)中。
02 | public static function insertRole($role_name){ |
03 | $sql = "INSERT INTO roles(role_name) VALUES (:role_name)"; |
04 | $sth = $GLOBALS['DB']->prepare($sql); |
05 | return $sth->execute(array(":role_name" => $role_name)); |
08 | public static function insertUserRoles($user_id, $roles){ |
09 | $sql = "INSERT INTO user_role(user_id, role_id) VALUES(:user_id, :role_id)"; |
10 | $sth = $GLOBALS['DB']->prepare($sql); |
11 | $sth->bindParam(":user_id", $user_id, PDO::PARAM_STR); |
12 | $sth->bindParam(":role_id", $role_id, PDO::PARAM_STR); |
13 | foreach($roles as $role_id){ |
19 | public static function deleteRoles($roles) { |
20 | $sql = "DELETE t1, t2, t3 FROM roles as t1 |
21 | JOIN user_role as t2 on t1.role_id = t2.role_id |
22 | JOIN role_perm as t3 on t1.role_id = t3.role_id |
23 | WHERE t1.role_id = :role_id"; |
24 | $sth = $GLOBALS["DB"]->prepare($sql); |
25 | $sth->bindParam(":role_id", $role_id, PDO::PARAM_INT); |
26 | foreach ($roles as $role_id) { |
32 | public static function deleteUserRoles($user_id) { |
33 | $sql = "DELETE FROM user_role WHERE user_id = :user_id"; |
34 | $sth = $GLOBALS["DB"]->prepare($sql); |
35 | return $sth->execute(array(":user_id" => $user_id)); |
把下面的方法加入到privilegedUser类中
02 | public function hasRole($role_name) { |
03 | return isset($this->roles[$role_name]); |
07 | public static function insertPerm($role_id, $perm_id) { |
08 | $sql = "INSERT INTO role_perm (role_id, perm_id) VALUES (:role_id, :perm_id)"; |
09 | $sth = $GLOBALS["DB"]->prepare($sql); |
10 | return $sth->execute(array(":role_id" => $role_id, ":perm_id" => $perm_id)); |
14 | public static function deletePerms() { |
15 | $sql = "TRUNCATE role_perm"; |
16 | $sth = $GLOBALS["DB"]->prepare($sql); |
17 | return $sth->execute(); |
也可以添加自己的角色权限管理方法。