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中的实现trim函数代码
Mar 19 PHP
深入php 正则表达式的学习探讨
Jun 06 PHP
PHP中redis的用法深入解析
Feb 20 PHP
PHP 正则表达式常用函数
Aug 17 PHP
浅谈php优化需要注意的地方
Nov 27 PHP
日常整理PHP中简单的图形处理(经典)
Oct 26 PHP
4种PHP异步执行的常用方式
Dec 24 PHP
Zend Framework教程之Bootstrap类用法概述
Mar 14 PHP
Laravel5.1自定义500错误页面示例
Oct 09 PHP
PHP正则删除HTML代码中宽高样式的方法
Jun 12 PHP
PHP全局使用Laravel辅助函数dd
Dec 26 PHP
tp5框架基于Ajax实现列表无刷新排序功能示例
Feb 10 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中使用XML
2006/10/09 PHP
深入PHP内存相关的功能特性详解
2013/06/08 PHP
一个php短网址的生成代码(仿微博短网址)
2014/05/07 PHP
php简单实现查询数据库返回json数据
2015/04/16 PHP
php获得文件夹下所有文件的递归算法的简单实例
2016/11/01 PHP
laravel-admin表单提交隐藏一些数据,回调时获取数据的方法
2019/10/08 PHP
解决php用mysql方式连接数据库出现Deprecated报错问题
2019/12/25 PHP
javascript语句中的CDATA标签的意义
2007/05/09 Javascript
JavaScript中的Window窗口对象
2008/01/16 Javascript
传智播客学习之JavaScript基础篇
2009/11/13 Javascript
JQuery动态给table添加、删除行 改进版
2011/01/19 Javascript
javascript 拷贝节点cloneNode()使用介绍
2014/04/03 Javascript
JavaScript sub方法入门实例(把字符串显示为下标)
2014/10/17 Javascript
JavaScript中的fontsize()方法使用详解
2015/06/08 Javascript
自己动手写的javascript前端等待控件
2015/10/30 Javascript
mpvue中使用flyjs全局拦截的实现代码
2018/09/13 Javascript
如何在 JavaScript 中更好地利用数组
2018/09/27 Javascript
原生javascript单例模式的应用实例分析
2020/02/23 Javascript
创建与框架无关的JavaScript插件
2020/12/01 Javascript
python Django模板的使用方法(图文)
2013/11/04 Python
Python列表(list)、字典(dict)、字符串(string)基本操作小结
2014/11/28 Python
微信跳一跳python辅助软件思路及图像识别源码解析
2018/01/04 Python
Python3 串口接收与发送16进制数据包的实例
2019/06/12 Python
python3 实现口罩抽签的功能
2020/03/11 Python
Jupyter notebook 远程配置及SSL加密教程
2020/04/14 Python
python爬取代理ip的示例
2020/12/18 Python
html5 input元素新特性_动力节点Java学院整理
2017/07/06 HTML / CSS
详解如何用canvas画一个微笑的表情
2019/03/14 HTML / CSS
HTML5 3D衣服摇摆动画特效
2016/03/17 HTML / CSS
附答案的Java面试题
2012/11/19 面试题
实用求职信范文分享
2013/12/25 职场文书
致全体运动员广播稿
2014/02/01 职场文书
激情洋溢的毕业生就业求职信
2014/03/15 职场文书
2014年安全生产责任书
2014/07/22 职场文书
2016新年年会主持词
2015/07/06 职场文书
如何使用Maxwell实时同步mysql数据
2021/04/08 MySQL