关于用户权限,有几种不同的处理方法,如位运算和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(); |
也可以添加自己的角色权限管理方法。