当前位置:首页 > CMS教程 > Thinkphp > 列表

ThinkPHP权限认证Auth实例详解

发布:smiling 来源: PHP粉丝网  添加日期:2021-03-23 11:48:14 浏览: 评论:0 

这篇文章主要介绍了ThinkPHP权限认证Auth实例,需要的朋友可以参考下

本文以实例代码的形式深入剖析了ThinkPHP权限认证Auth的实现原理与方法,具体步骤如下:

mysql数据库部分sql代码:

  1. -- ---------------------------- 
  2. -- Table structure for think_auth_group 
  3. -- ---------------------------- 
  4. DROP TABLE IF EXISTS `think_auth_group`; 
  5. CREATE TABLE `think_auth_group` ( 
  6.  `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, 
  7.  `title` char(100) NOT NULL DEFAULT ''
  8.  `status` tinyint(1) NOT NULL DEFAULT '1'
  9.  `rules` char(80) NOT NULL DEFAULT ''
  10.  PRIMARY KEY (`id`) 
  11. ) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='用户组表'
  12.  
  13. -- ---------------------------- 
  14. -- Records of think_auth_group 
  15. -- ---------------------------- 
  16. INSERT INTO `think_auth_group` VALUES ('1''管理组''1''1,2'); 
  17.  
  18. -- ---------------------------- 
  19. -- Table structure for think_auth_group_access 
  20. -- ---------------------------- 
  21. DROP TABLE IF EXISTS `think_auth_group_access`; 
  22. CREATE TABLE `think_auth_group_access` ( 
  23.  `uid` mediumint(8) unsigned NOT NULL COMMENT '用户id'
  24.  `group_id` mediumint(8) unsigned NOT NULL COMMENT '用户组id'
  25.  UNIQUE KEY `uid_group_id` (`uid`,`group_id`), 
  26.  KEY `uid` (`uid`), 
  27.  KEY `group_id` (`group_id`) 
  28. ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='用户组明细表'
  29.  
  30. -- ---------------------------- 
  31. -- Records of think_auth_group_access 
  32. -- ---------------------------- 
  33. INSERT INTO `think_auth_group_access` VALUES ('1''1'); 
  34. INSERT INTO `think_auth_group_access` VALUES ('1''2'); 
  35.  
  36. -- ---------------------------- 
  37. -- Table structure for think_auth_rule 
  38. -- ---------------------------- 
  39. DROP TABLE IF EXISTS `think_auth_rule`; 
  40. CREATE TABLE `think_auth_rule` ( 
  41.  `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, 
  42.  `name` char(80) NOT NULL DEFAULT '' COMMENT '规则唯一标识'
  43.  `title` char(20) NOT NULL DEFAULT '' COMMENT '规则中文名称'
  44.  `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态:为1正常,为0禁用'
  45.  `type` char(80) NOT NULL, 
  46.  `condition` char(100) NOT NULL DEFAULT '' COMMENT '规则表达式,为空表示存在就验证,不为空表示按照条件验证'
  47.  PRIMARY KEY (`id`), 
  48.  UNIQUE KEY `name` (`name`) 
  49. ) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='规则表'
  50.  
  51. -- ---------------------------- 
  52. -- Records of think_auth_rule 
  53. -- ---------------------------- 
  54. INSERT INTO `think_auth_rule` VALUES ('1''Home/index''列表''1''Home'''); 
  55. INSERT INTO `think_auth_rule` VALUES ('2''Home/add''添加''1''Home'''); 
  56. INSERT INTO `think_auth_rule` VALUES ('3''Home/edit''编辑''1''Home'''); 
  57. INSERT INTO `think_auth_rule` VALUES ('4''Home/delete''删除''1''Home'''); 
  58.  
  59.  
  60. DROP TABLE IF EXISTS `think_user`; 
  61. CREATE TABLE `think_user` ( 
  62.  `id` int(11) NOT NULL, 
  63.  `username` varchar(30) DEFAULT NULL, 
  64.  `password` varchar(32) DEFAULT NULL, 
  65.  `age` tinyint(2) DEFAULT NULL, 
  66.  PRIMARY KEY (`id`) 
  67. ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
  68.  
  69. -- ---------------------------- 
  70. -- Records of think_user 
  71. -- ---------------------------- 
  72. INSERT INTO `think_user` VALUES ('1''admin''21232f297a57a5a743894a0e4a801fc3''25'); 

配置文件Application\Common\Conf\config.php部分:

  1. <?php 
  2.  
  3. return array( 
  4.  //'配置项'=>'配置值' 
  5.  'DB_DSN' => '', // 数据库连接DSN 用于PDO方式 
  6.  'DB_TYPE' => 'mysql', // 数据库类型 
  7.  'DB_HOST' => 'localhost', // 服务器地址 
  8.  'DB_NAME' => 'thinkphp', // 数据库名 
  9.  'DB_USER' => 'root', // 用户名 
  10.  'DB_PWD' => 'root', // 密码 
  11.  'DB_PORT' => 3306, // 端口 
  12.  'DB_PREFIX' => 'think_', // 数据库表前缀  
  13.    
  14.  'AUTH_CONFIG' => array( 
  15.   'AUTH_ON' => true, //认证开关 
  16.   'AUTH_TYPE' => 1, // 认证方式,1为时时认证;2为登录认证。 
  17.   'AUTH_GROUP' => 'think_auth_group', //用户组数据表名 
  18.   'AUTH_GROUP_ACCESS' => 'think_auth_group_access', //用户组明细表 
  19.   'AUTH_RULE' => 'think_auth_rule', //权限规则表 
  20.   'AUTH_USER' => 'think_user'//用户信息表 
  21.  ) 
  22. ); 

项目Home控制器部分Application\Home\Controller\IndexController.class.php代码:

  1. <?php 
  2. namespace Home\Controller; 
  3. use Think\Controller; 
  4. class IndexController extends Controller { 
  5.  public function index() { 
  6.   $Auth = new \Think\Auth(); 
  7.   //需要验证的规则列表,支持逗号分隔的权限规则或索引数组 
  8.   $name = MODULE_NAME . '/' . ACTION_NAME; 
  9.   //当前用户id 
  10.   $uid = '1'
  11.   //分类 
  12.   $type = MODULE_NAME; 
  13.   //执行check的模式 
  14.   $mode = 'url'
  15.   //'or' 表示满足任一条规则即通过验证; 
  16.   //'and'则表示需满足所有规则才能通过验证 
  17.   $relation = 'and'
  18.   if ($Auth->check($name$uid$type$mode$relation)) { 
  19.    die('认证:成功'); 
  20.   } else { 
  21.    die('认证:失败'); 
  22.   } 
  23.  } 

以上这些代码就是最基本的验证代码示例。

下面是源码阅读:

1、权限检验类初始化配置信息:

$Auth = new \Think\Auth();

创建一个对象时程序会合并配置信息

程序会合并Application\Common\Conf\config.php中的AUTH_CONFIG数组

  1. public function __construct() { 
  2.  $prefix = C('DB_PREFIX'); 
  3.  $this->_config['AUTH_GROUP'] = $prefix . $this->_config['AUTH_GROUP']; 
  4.  $this->_config['AUTH_RULE'] = $prefix . $this->_config['AUTH_RULE']; 
  5.  $this->_config['AUTH_USER'] = $prefix . $this->_config['AUTH_USER']; 
  6.  $this->_config['AUTH_GROUP_ACCESS'] = $prefix . $this->_config['AUTH_GROUP_ACCESS']; 
  7.  if (C('AUTH_CONFIG')) { 
  8.   //可设置配置项 AUTH_CONFIG, 此配置项为数组。 
  9.   $this->_config = array_merge($this->_config, C('AUTH_CONFIG')); 
  10.  } 

2、检查权限:

check($name, $uid, $type = 1, $mode = 'url', $relation = 'or')

大体分析一下这个方法

首先判断是否关闭权限校验 如果配置信息AUTH_ON=>false 则不会进行权限验证 否则继续验证权限

  1. if (!$this->_config['AUTH_ON']) { 
  2.  return true; 

获取权限列表之后会详细介绍:

$authList = $this->getAuthList($uid, $type);

此次需要验证的规则列表转换成数组:

  1. if (is_string($name)) { 
  2.  $name = strtolower($name); 
  3.  if (strpos($name',') !== false) { 
  4.  $name = explode(','$name); 
  5.  } else { 
  6.  $name = array($name); 
  7.  } 

所以$name参数是不区分大小写的,最终都会转换成小写

开启url模式时全部转换为小写:

  1. if ($mode == 'url') { 
  2.  $REQUEST = unserialize(strtolower(serialize($_REQUEST))); 

权限校验核心代码段之一,即循环所有该用户权限 判断 当前需要验证的权限 是否 在用户授权列表中:

  1. foreach ($authList as $auth) { 
  2.  $query = preg_replace('/^.+\?/U'''$auth);//获取url参数 
  3.  if ($mode == 'url' && $query != $auth) { 
  4.  parse_str($query$param); //获取数组形式url参数 
  5.  $intersect = array_intersect_assoc($REQUEST$param); 
  6.  $auth = preg_replace('/\?.*$/U'''$auth);//获取访问的url文件 
  7.  if (in_array($auth$name) && $intersect == $param) { //如果节点相符且url参数满足 
  8.   $list[] = $auth
  9.  } 
  10.  } else if (in_array($auth$name)) { 
  11.  $list[] = $auth
  12.  } 

in_array($auth, $name) 如果 权限列表中 其中一条权限 等于 当前需要校验的权限 则加入到$list中

注:

  1. $list = array(); //保存验证通过的规则名 
  2.  
  3. if ($relation == 'or' and !emptyempty($list)) { 
  4.  return true; 
  5.  
  6. $diff = array_diff($name$list); 
  7. if ($relation == 'and' and emptyempty($diff)) { 
  8.  return true; 
  9.  
  10. $relation == 'or' and !emptyempty($list); //当or时 只要有一条是通过的 则 权限为真 
  11. $relation == 'and' and emptyempty($diff); //当and时 $name与$list完全相等时 权限为真 

3、获取权限列表:

$authList = $this->getAuthList($uid, $type); //获取用户需要验证的所有有效规则列表

这个主要流程:

获取用户组

  1. $groups = $this->getGroups($uid); 
  2. //SELECT `rules` FROM think_auth_group_access a INNER JOIN think_auth_group g on a.group_id=g.id WHERE ( a.uid='1' and g.status='1' ) 

简化操作就是:

SELECT `rules` FROM think_auth_group WHERE STATUS = '1' AND id='1'//按正常流程 去think_auth_group_access表中内联有点多余....!

取得用户组rules规则字段 这个字段中保存的是think_auth_rule规则表的id用,分割

$ids就是$groups变量最终转换成的 id数组:

  1. $map = array
  2.  'id' => array('in'$ids), 
  3.  'type' => $type
  4.  'status' => 1, 
  5. ); 

取得think_auth_rule表中的规则信息,之后循环:

  1. foreach ($rules as $rule) { 
  2.   if (!emptyempty($rule['condition'])) { //根据condition进行验证 
  3.   $user = $this->getUserInfo($uid); //获取用户信息,一维数组 
  4.   $command = preg_replace('/\{(\w*?)\}/''$user[\'\\1\']'$rule['condition']); 
  5.   //dump($command);//debug 
  6.   @(eval('$condition=(' . $command . ');')); 
  7.   if ($condition) { 
  8.    $authList[] = strtolower($rule['name']); 
  9.   } 
  10.   } else { 
  11.   //只要存在就记录 
  12.   $authList[] = strtolower($rule['name']); 
  13.   } 
  14.  } 
  15. if (!emptyempty($rule['condition'])) { //根据condition进行验证 

这里就可以明白getUserInfo 会去获取配置文件AUTH_USER对应表名 去查找用户信息

重点是:

$command = preg_replace('/\{(\w*?)\}/', '$user[\'\\1\']', $rule['condition']);

@(eval('$condition=(' . $command . ');'));

'/\{(\w*?)\}/ 可以看成要匹配的文字为 {字符串} 那么 {字符串} 会替换成$user['字符串']

$command =$user['字符串']

如果

  1. $rule['condition'] = '{age}'
  2. $command =$user['age'
  3. $rule['condition'] = '{age} > 5'
  4. $command =$user['age'] > 10 
  5. @(eval('$condition=(' . $command . ');')); 

即:

$condition=($user['age'] > 10);

这时再看下面代码 如果为真则加为授权列表

  1. if ($condition) { 
  2.   $authList[] = strtolower($rule['name']); 

Tags: ThinkPHP权限认证 Auth

分享到: