RBAC类使用

时间:2023-03-09 08:27:01
RBAC类使用

1.实现
首先我们先简单理解一下RBAC,顾名思义,RBAC是基于角色的权限设计。既然根据角色去分权限,那么我们就得有角色表,权限表,角色对应权限表,这是最基本的。角色是什么,就是你的身份,你的职位,也就是一个用户拥有这个身份才能获得某种权力。插一句,角色下辖的是用户,一个角色组可以有多个用户,一个用户也可能有多个角色,多对多的关系。
打开RBAC.class.php,你会发现官方已经告诉你,需要准备的东西。首先是配置文件需要设置的东西如下:

  1. // 配置文件增加设置
  2. // USER_AUTH_ON 是否需要认证
  3. // USER_AUTH_TYPE 认证类型 1 登录认证 2 实时认证
  4. // USER_AUTH_KEY 认证识别号
  5. // REQUIRE_AUTH_MODULE  需要认证模块
  6. // NOT_AUTH_MODULE 无需认证模块
  7. // USER_AUTH_GATEWAY 认证网关
  8. // RBAC_DB_DSN  数据库连接DSN
  9. // RBAC_ROLE_TABLE 角色表名称
  10. // RBAC_USER_TABLE 用户表名称
  11. // RBAC_ACCESS_TABLE 权限表名称
  12. // RBAC_NODE_TABLE 节点表名称
  1. /*
  2. -- --------------------------------------------------------
  3. CREATE TABLE IF NOT EXISTS `think_access` (
  4. `role_id` smallint(6) unsigned NOT NULL,
  5. `node_id` smallint(6) unsigned NOT NULL,
  6. `level` tinyint(1) NOT NULL,
  7. `module` varchar(50) DEFAULT NULL,
  8. KEY `groupId` (`role_id`),
  9. KEY `nodeId` (`node_id`)
  10. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  11. CREATE TABLE IF NOT EXISTS `think_node` (
  12. `id` smallint(6) unsigned NOT NULL AUTO_INCREMENT,
  13. `name` varchar(20) NOT NULL,
  14. `title` varchar(50) DEFAULT NULL,
  15. `status` tinyint(1) DEFAULT '0',
  16. `remark` varchar(255) DEFAULT NULL,
  17. `sort` smallint(6) unsigned DEFAULT NULL,
  18. `pid` smallint(6) unsigned NOT NULL,
  19. `level` tinyint(1) unsigned NOT NULL,
  20. PRIMARY KEY (`id`),
  21. KEY `level` (`level`),
  22. KEY `pid` (`pid`),
  23. KEY `status` (`status`),
  24. KEY `name` (`name`)
  25. ) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
  26. CREATE TABLE IF NOT EXISTS `think_role` (
  27. `id` smallint(6) unsigned NOT NULL AUTO_INCREMENT,
  28. `name` varchar(20) NOT NULL,
  29. `pid` smallint(6) DEFAULT NULL,
  30. `status` tinyint(1) unsigned DEFAULT NULL,
  31. `remark` varchar(255) DEFAULT NULL,
  32. PRIMARY KEY (`id`),
  33. KEY `pid` (`pid`),
  34. KEY `status` (`status`)
  35. ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 ;
  36. CREATE TABLE IF NOT EXISTS `think_role_user` (
  37. `role_id` mediumint(9) unsigned DEFAULT NULL,
  38. `user_id` char(32) DEFAULT NULL,
  39. KEY `group_id` (`role_id`),
  40. KEY `user_id` (`user_id`)
  41. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;

2.RBAC类方法

1。authenticate()// 认证方法,检查是否传入用户模型
你需要在配置文件中定义USER_AUTH_MODEL,一般值是User,这个是你的用户表名称,根据实际情况填写。
2。saveAccessList($authId=null)//用于检测用户权限的方法,并保存到Session中
3。getRecordAccessList($authId=null,$module='')// 取得模块的所属记录访问权限列表 返回有权限的记录ID数组
4。checkAccess() //检查当前操作是否需要认证
5。checkLogin()// 登录检查这个是很重要的方法,我们会用了检测用户是否登录
6。AccessDecision($appName=APP_NAME)//权限认证的过滤器方法
7。getAccessList($authId)//取得当前认证号的所有权限列表
8.getModuleAccessList($authId,$module)// 读取模块所属的记录访问权限
官方类文件注释比较详细,我也就不再赘述。主要讲解一下实际用法。
上一次我已经说了第一步是建好相关表和配置文件,接下来才是写代码。这里先补充一下,配置文件参数实例:

  1. 'USER_AUTH_ON'            =>        true,             //开启认证
  2. 'USER_AUTH_TYPE'        =>        1,              //用户认证使用SESSION标记
  3. 'USER_AUTH_KEY'            =>        'authId',          //设置认证SESSION的标记名称
  4. 'ADMIN_AUTH_KEY'        =>        'admin',        //管理员用户标记
  5. 'USER_AUTH_MODEL'        =>        'User',          //验证用户的表模型u_user
  6. 'AUTH_PWD_ENCODER'        =>        'md5',             //用户认证密码加密方式
  7. 'USER_AUTH_GATEWAY'        =>        '/Public/login',//默认的认证网关
  8. 'NOT_AUTH_MODULE'        =>        'Public,Index',          //默认不需要认证的模块'A,B,C'
  9. 'REQUIRE_AUTH_MODULE'    =>        '',              //默认需要认证的模块
  10. 'NOT_AUTH_ACTION'        =>        '',                //默认不需要认证的动作
  11. 'REQUIRE_AUTH_ACTION'    =>        '',                //默认需要认证的动作
  12. 'GUEST_AUTH_ON'            =>        false,            //是否开启游客授权访问
  13. 'GUEST_AUTH_ID'            =>        0,                 //游客标记
  14. 'RBAC_ROLE_TABLE'        =>        'tao_role',       //角色表
  15. 'RBAC_USER_TABLE'        =>        'tao_role_user', //角色分配表
  16. 'RBAC_ACCESS_TABLE'        =>        'tao_access',   //权限分配表
  17. 'RBAC_NODE_TABLE'        =>        'tao_node',     //节点表

你在conf文件夹下的config.php中需写入以上配置参数。
接下来我讲解一下,RBAC的验证流程,首先用户访问某个页面,程序判断是否为公开,不是则跳转到登录页面。登录成功,判断是否有权限访问,没有提示权限错误信息。同样点击某项操作或者模块也是检测是否有权限。结合上面那个类,第一步其实我们是判断访问的操作或者模块是在公开访问的模块组,或者说在不需要验证的模块组,即判断C('NOT_AUTH_MODULE')中有没有该模块,有则为公开组不需要登录,反之跳转到登录页面。登录页面执行checkLogin方法,验证通过跳转到默认首页。在用户操作链接时触发AccessDecision方法,其实这个方法内部调用了检查权限的checkAccess方法,有权限继续操作,没有提示错误。(注:这里其实是先判断了当前用户属于哪个用户组,然后判断用户组具有哪些权限)

3.实例

登录验证部分实例
上一讲我已经说了RBAC的流程,这次通过实际代码来分析。首先讲登录部分,登录无非就是验证用户名密码以及验证码是否正确,我们可以新建一个CommonAction的公共类,用来校验权限,其他所有类继承此类。该类内部写一个初始化方法,用于验证,这一讲先不详细讲解。继续说登录,由于登录是公开模块的方法,所以可以新建一个PublicAction类,用于公共的免验证方法,同时在配置文件中添加

  1. 'NOT_AUTH_MODULE'        =>        'Public',          //默认不需要认证的模块
  2. 'USER_AUTH_GATEWAY'        =>        '/Public/login',//默认的认证网关

然后开始编写Public类,具体代码如下:

  1. <?php
  2. class PublicAction extends CommonAction{
  3. //验证码显示
  4. public function verify(){
  5. import("ORG.Util.Image");
  6. Image::buildImageVerify(4,1,"png",100,28,"verify");
  7. }
  8. //验证是否账号密码
  9. function checklogin(){
  10. //此处多余可自行改为Model自动验证
  11. if(empty($_POST['username'])) {
  12. $this->error('帐号错误!');
  13. }elseif (empty($_POST['password'])){
  14. $this->error('密码必须!');
  15. }elseif (empty($_POST['verify'])){
  16. $this->error('验证码必须!');
  17. }
  18. $map=array();
  19. $map['username']=$_POST['username'];
  20. $map['status']=array('gt',0);
  21. if($_SESSION['verify'] != md5($_POST['verify'])) {
  22. $this->error('验证码错误!');
  23. }
  24. import('ORG.Util.RBAC');
  25. //C('USER_AUTH_MODEL','User');
  26. //验证账号密码
  27. $authInfo=RBAC::authenticate($map);
  28. if(empty($authInfo)){
  29. $this->error('账号不存在或者被禁用!');
  30. }else{
  31. if($authInfo['password']!=md5($_POST['password'])){
  32. $this->error('账号密码错误!');
  33. }else{
  34. $_SESSION[C('USER_AUTH_KEY')]=$authInfo['id'];//记录认证标记,必须有。其他信息根据情况取用。
  35. $_SESSION['email']=$authInfo['email'];
  36. $_SESSION['nickname']=$authInfo['nickname'];
  37. $_SESSION['user']=$authInfo['username'];
  38. $_SESSION['last_login_date']=$authInfo['last_login_date'];
  39. $_SESSION['last_login_ip']=$authInfo['last_login_ip'];
  40. //判断是否为超级管理员
  41. if($authInfo['username']=='admin'){
  42. $_SESSION[C('ADMIN_AUTH_KEY')]=true;
  43. }
  44. //以下操作为记录本次登录信息
  45. $user=M('User');
  46. $lastdate=date('Y-m-d H:i:s');
  47. $data=array();
  48. $data['id']=$authInfo['id'];
  49. $data['last_login_date']=$lastdate;
  50. $data['last_login_ip']=$_SERVER["REMOTE_ADDR"];
  51. $user->save($data);
  52. RBAC::saveAccessList();//用于检测用户权限的方法,并保存到Session中
  53. $this->assign('jumpUrl',.'/Index/index');
  54. $this->success('登录成功!');
  55. }
  56. }
  57. }
  58. //退出登录操作
  59. function logout(){
  60. if(!empty($_SESSION[C('USER_AUTH_KEY')])){
  61. unset($_SESSION[C('USER_AUTH_KEY')]);
  62. $_SESSION=array();
  63. session_destroy();
  64. $this->assign('jumpUrl',/Code.'/login');
  65. $this->success('登出成功');
  66. }else{
  67. $this->error('已经登出了');
  68. }
  69. }
  70. }

以上代码仅实现功能,没有做优化,有些验证的操作可以放到model,session也不用一 一赋值,用数组即可,我想已经入门的应该可以自己改的更好

4.

权限校验部分
新建CommonAction类文件,写入以下代码

    1. <?php
    2. class CommonAction extends Action{
    3. //初始化方法,调用方法时会先执行
    4. function _initialize(){
    5. header('Content-Type:text/html;charset=utf-8');
    6. import('ORG.Util.Cookie');
    7. // 用户权限检查
    8. if (C('USER_AUTH_ON') && !in_array(MODULE_NAME, explode(',', C('NOT_AUTH_MODULE')))) {
    9. import('ORG.Util.RBAC');
    10. if (!RBAC::AccessDecision()) {
    11. //检查认证识别号
    12. if (!$_SESSION [C('USER_AUTH_KEY')]) {
    13. //跳转到认证网关
    14. redirect(PHP_FILE . C('USER_AUTH_GATEWAY'));
    15. }else{
    16. echo L('_VALID_ACCESS_');
    17. exit();
    18. }
    19. // 没有权限 抛出错误
    20. if (C('RBAC_ERROR_PAGE')) {
    21. // 定义权限错误页面
    22. redirect(C('RBAC_ERROR_PAGE'));
    23. } else {
    24. if (C('GUEST_AUTH_ON')) {
    25. $this->assign('jumpUrl', PHP_FILE . C('USER_AUTH_GATEWAY'));
    26. }
    27. // 提示错误信息
    28. $this->error(L('_VALID_ACCESS_'));
    29. }
    30. }
    31. }
    32. }