ThinkPHP令牌验证实例


Posted in PHP onJune 18, 2014

ThinkPHP内置了表单令牌验证功能,可以有效防止表单的远程提交等安全防护。
表单令牌验证相关的配置参数有:

'TOKEN_ON'=>true, // 是否开启令牌验证 
'TOKEN_NAME'=>'__hash__', // 令牌验证的表单隐藏字段名称 
'TOKEN_TYPE'=>'md5', //令牌哈希验证规则 默认为MD5

如果开启表单令牌验证功能,系统会自动在带有表单的模板文件里面自动生成以TOKEN_NAME为名称的隐藏域,其值则是TOKEN_TYPE方式生成的哈希字符串,用于实现表单的自动令牌验证。

自动生成的隐藏域位于表单Form结束标志之前,如果希望自己控制隐藏域的位置,可以手动在表单页面添加__TOKEN__ 标识,系统会在输出模板的时候自动替换。如果在开启表单令牌验证的情况下,个别表单不需要使用令牌验证功能,可以在表单页面添加__NOTOKEN__,则系统会忽略当前表单的令牌验证。

如果页面中存在多个表单,建议添加__TOKEN__标识,并确保只有一个表单需要令牌验证。

模型类在创建数据对象的同时会自动进行表单令牌验证操作,如果你没有使用create方法创建数据对象的话,则需要手动调用模型的autoCheckToken方法进行表单令牌验证。如果返回false,则表示表单令牌验证错误。例如:

$User = M("User"); // 实例化User对象 
// 手动进行令牌验证 
if (!$User->autoCheckToken($_POST)){ 
// 令牌验证错误 
}

在ThinkPHP框架的View.class.php里定义了一个公共的模板替换函数

protected function templateContentReplace($content) {
 // 系统默认的特殊变量替换
 $replace = array(
 '../Public' => APP_PUBLIC_PATH,// 项目公共目录
 '__PUBLIC__' => WEB_PUBLIC_PATH,// 站点公共目录
 '__TMPL__' => APP_TMPL_PATH, // 项目模板目录
 '__ROOT__' => __ROOT__, // 当前网站地址
 '__APP__' => __APP__, // 当前项目地址
 '__UPLOAD__' => __ROOT__.'/Uploads',
 '__ACTION__' => __ACTION__, // 当前操作地址
 '__SELF__' => __SELF__, // 当前页面地址
 '__URL__' => __URL__,
 '__INFO__' => __INFO__,
 );
 if(defined('GROUP_NAME'))
 {
 $replace['__GROUP__'] = __GROUP__;// 当前项目地址
 }
 if(C('TOKEN_ON')) {
 if(strpos($content,'{__TOKEN__}')) {
 // 指定表单令牌隐藏域位置
 $replace['{__TOKEN__}'] = $this->buildFormToken();
 }elseif(strpos($content,'{__NOTOKEN__}')){
 // 标记为不需要令牌验证
 $replace['{__NOTOKEN__}'] = '';
 }elseif(preg_match('/<\/form(\s*)>/is',$content,$match)) {
 // 智能生成表单令牌隐藏域
 $replace[$match[0]] = $this->buildFormToken().$match[0];
 }
 }
 // 允许用户自定义模板的字符串替换
 if(is_array(C('TMPL_PARSE_STRING')) )
 $replace = array_merge($replace,C('TMPL_PARSE_STRING'));
 $content = str_replace(array_keys($replace),array_values($replace),$content);
 return $content;
 }

上面的if(C('TOKEN_ON'))是对令牌验证的开启状态进行判断,若开启则调用buildFormToken()方法,$_SESSION[$tokenName] = $tokenValue; 其实就是给$_SESSION['__hash__']赋值。如果不想进行令牌验证,只要在页面的</form>之前加入{__NOTOKEN__}就行了,它会被函数替换成空。

在ThinkPHP的Model.class.php类里定义了令牌的验证函数

// 表单令牌验证
 if(C('TOKEN_ON') && !$this->autoCheckToken($data)) {
 $this->error = L('_TOKEN_ERROR_');
 return false;
 }

 // 自动表单令牌验证
 public function autoCheckToken($data) {
 $name = C('TOKEN_NAME');
 if(isset($_SESSION[$name])) {
 // 当前需要令牌验证
 if(empty($data[$name]) || $_SESSION[$name] != $data[$name]) {
 // 非法提交
 return false;
 }
 // 验证完成销毁session
 unset($_SESSION[$name]);
 }
 return true;
 }
PHP 相关文章推荐
php 无限级分类学习参考之对ecshop无限级分类的解析 带详细注释
Mar 23 PHP
CodeIgniter图像处理类的深入解析
Jun 17 PHP
php删除字符串末尾子字符,删除开始字符,删除两端字符(实现代码)
Jun 27 PHP
PHP图片自动裁切应付不同尺寸的显示
Oct 16 PHP
php实现简单的上传进度条
Nov 17 PHP
Symfony2框架学习笔记之表单用法详解
Mar 18 PHP
初识ThinkPHP控制器
Apr 07 PHP
php图像处理函数imagecopyresampled用法详解
Dec 02 PHP
PHP机器学习库php-ml的简单测试和使用方法
Jul 14 PHP
php多进程模拟并发事务产生的问题小结
Dec 07 PHP
PHP实现网站应用微信登录功能详解
Apr 11 PHP
用php如何解决大文件分片上传问题
Jul 07 PHP
Smarty局部缓存的几种方法简介
Jun 17 #PHP
smarty模板局部缓存方法使用示例
Jun 17 #PHP
CodeIgniter CLI模式简介
Jun 17 #PHP
CI框架在CLI下执行占用内存过大问题的解决方法
Jun 17 #PHP
CI框架自动加载session出现报错的解决办法
Jun 17 #PHP
Thinkphp模板中截取字符串函数简介
Jun 17 #PHP
CI框架中zip类应用示例
Jun 17 #PHP
You might like
关于url地址传参数时字符串有回车造成页面脚本赋值失败的解决方法
2013/06/28 PHP
jquery+php实现导出datatables插件数据到excel的方法
2015/07/06 PHP
php计划任务之验证是否有多个进程调用同一个job的方法
2015/12/07 PHP
PHP在线打包下载功能示例
2016/10/15 PHP
PHP XML和数组互相转换详解
2016/10/26 PHP
php生成图片缩略图功能示例
2017/02/22 PHP
PHPMailer使用QQ邮箱实现邮件发送功能
2017/08/18 PHP
使用隐藏的new来创建对象
2011/03/29 Javascript
JavaScript中的isXX系列是否继续使用的分析
2011/04/16 Javascript
js中document.write使用过程中的一点疑问解答
2014/03/20 Javascript
jQuery插件开发的五种形态小结
2015/03/04 Javascript
原生js实现电商侧边导航效果
2017/01/19 Javascript
深入探究node之Transform
2017/07/20 Javascript
基于JavaScript实现选项卡效果
2017/07/21 Javascript
实现一个完整的Node.js RESTful API的示例
2017/09/29 Javascript
Node.js 中使用 async 函数的方法
2017/11/20 Javascript
JS中call和apply函数用法实例分析
2018/06/20 Javascript
Vue实现用户自定义字段显示数据的方法
2018/08/28 Javascript
vue路由--网站导航功能详解
2019/03/29 Javascript
vue使用自定义指令实现拖拽
2021/01/29 Javascript
在Mac OS上搭建Python的开发环境
2015/12/24 Python
python中利用Future对象异步返回结果示例代码
2017/09/07 Python
Python3正则匹配re.split,re.finditer及re.findall函数用法详解
2018/06/11 Python
python实现WebSocket服务端过程解析
2019/10/18 Python
迪卡侬比利时官网:Decathlon比利时
2019/12/28 全球购物
企业面试题试卷附带答案
2015/12/20 面试题
Laravel中Kafka的使用详解
2021/03/24 PHP
高一生物教学反思
2014/01/17 职场文书
店面销售职位的职责
2014/03/09 职场文书
公益广告语集锦
2014/03/13 职场文书
2014年全国爱牙日宣传活动方案
2014/09/21 职场文书
2014群众路线学习笔记
2014/11/06 职场文书
关于清明节的演讲稿2015
2015/03/18 职场文书
2016高考感言
2015/08/01 职场文书
MySQL的Query Cache图文详解
2021/07/01 MySQL
SQL Server实现分页方法介绍
2022/03/16 SQL Server