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 相关文章推荐
一个好用的分页函数
Nov 16 PHP
source.php查看源文件
Dec 09 PHP
php 取得瑞年与平年的天数的代码
Aug 10 PHP
PHP 强制性文件下载功能的函数代码(任意文件格式)
May 26 PHP
在PHP中PDO解决中文乱码问题的一些补充
Sep 06 PHP
php fputcsv命令 写csv文件遇到的小问题(多维数组连接符)
May 24 PHP
php取整函数ceil,floo,round的用法及介绍
Aug 31 PHP
php实现加减法验证码代码
Feb 14 PHP
PHP封装的Twitter访问类实例
Jul 18 PHP
用PHP将Unicode 转化为UTF-8的实现方法(推荐)
Feb 08 PHP
PHP使用函数用法详解
Sep 30 PHP
Laravel 框架控制器 Controller原理与用法实例分析
Apr 14 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
php输出表格的实现代码(修正版)
2010/12/29 PHP
解析php中static,const与define的使用区别
2013/06/18 PHP
实现在同一方法中获取当前方法中新赋值的session值解决方法
2014/06/26 PHP
Yii 2.0实现联表查询加搜索分页的方法示例
2017/08/02 PHP
基于PHP实现栈数据结构和括号匹配算法示例
2017/08/10 PHP
php 字符串中是否包含指定字符串的多种方法
2018/04/12 PHP
PHP5.0~5.6 各版本兼容性cURL文件上传功能实例分析
2018/05/11 PHP
浅谈PHP进程管理
2019/03/08 PHP
PHP常量DIRECTORY_SEPARATOR原理及用法解析
2020/11/10 PHP
在Javascript中为String对象添加trim,ltrim,rtrim方法
2006/09/22 Javascript
JavaScript 三种创建对象的方法
2009/10/16 Javascript
JS连连看源码完美注释版(推荐)
2013/12/09 Javascript
js正则表达式中test,exec,match方法的区别说明
2014/01/29 Javascript
js获得当前时区夏令时发生和终止的时间代码
2014/02/23 Javascript
Javscript调用iframe框架页面中函数的方法
2014/11/01 Javascript
Ionic快速安装教程
2016/06/03 Javascript
js中使用使用原型(prototype)定义方法的好处详解
2016/07/04 Javascript
简单理解vue中Props属性
2016/10/27 Javascript
vue中mint-ui环境搭建详细介绍
2017/04/06 Javascript
javascript实现简单搜索功能
2020/03/26 Javascript
JavaScript进阶(二)词法作用域与作用域链实例分析
2020/05/09 Javascript
Python help()函数用法详解
2014/03/11 Python
Python+matplotlib实现计算两个信号的交叉谱密度实例
2018/01/08 Python
解决Python网页爬虫之中文乱码问题
2018/05/11 Python
Python Flask框架模板操作实例分析
2019/05/03 Python
简单了解Python读取大文件代码实例
2019/12/18 Python
解决Django提交表单报错:CSRF token missing or incorrect的问题
2020/03/13 Python
解决Pycharm双击图标启动不了的问题(JetBrains全家桶通用)
2020/08/07 Python
python判断一个变量是否已经设置的方法
2020/08/13 Python
解决CSS3 transition-delay 属性默认值0不带单位失效的问题
2020/10/29 HTML / CSS
马来西亚时装购物网站:ZALORA马来西亚
2017/03/14 全球购物
哪些情况下不应该使用索引
2015/07/20 面试题
TCP协议通讯的过程和步骤是什么
2015/10/18 面试题
社区灵活就业证明
2014/11/03 职场文书
2016中考冲刺决心书
2015/09/22 职场文书
Python 文本滚动播放器的实现代码
2021/04/25 Python