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 友好URL的实现(吐血推荐)
Oct 04 PHP
提高PHP编程效率 引入缓存机制提升性能
Feb 15 PHP
PHP输出当前进程所有变量/常量/模块/函数/类的示例
Nov 07 PHP
ThinkPHP结合ajax、Mysql实现的客户端通信功能代码示例
Jun 23 PHP
PHP操作文件的一些基本函数使用示例
Nov 18 PHP
PHP原生函数一定好吗?
Dec 08 PHP
php文件系统处理方法小结
May 23 PHP
Laravel 的数据库迁移的方法
Jul 31 PHP
Laravel学习教程之View模块详解
Sep 18 PHP
PHP常用的类封装小结【4个工具类】
Jun 28 PHP
laravel框架实现后台登录、退出功能示例
Oct 31 PHP
TP5框架使用QueryList采集框架爬小说操作示例
Mar 26 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
ThinkPHP php 框架学习笔记
2009/10/30 PHP
php中关于codeigniter的xmlrpc的类在进行数据交换时的类型问题
2011/07/03 PHP
php堆排序(heapsort)练习
2013/11/13 PHP
PHP实现货币换算的方法
2014/11/29 PHP
php禁止某ip或ip地址段访问的方法
2015/02/25 PHP
php按单词截取字符串的方法
2015/04/07 PHP
零基础学JavaScript最新动画教程+iso光盘下载
2008/01/22 Javascript
uploadify在Firefox下丢失session问题的解决方法
2013/08/07 Javascript
JavaScript模块随意拖动示例代码
2014/05/27 Javascript
jquery实现类似EasyUI的页面布局可改变左右的宽度
2020/09/12 Javascript
jQuery中queue()方法用法实例
2014/12/29 Javascript
原生javascript实现隔行换色
2015/01/04 Javascript
js实现绿白相间竖向网页百叶窗动画切换效果
2015/03/02 Javascript
原生JS实现-星级评分系统的简单实例
2016/08/21 Javascript
javascript实现简单的on事件绑定
2016/08/23 Javascript
nodejs连接mysql数据库简单封装示例-mysql模块
2017/04/10 NodeJs
用JS实现根据当前时间随机生成流水号或者订单号
2018/05/31 Javascript
VeeValidate 的使用场景以及配置详解
2019/01/11 Javascript
Python验证码识别处理实例
2015/12/28 Python
21行Python代码实现拼写检查器
2016/01/25 Python
python list排序的两种方法及实例讲解
2017/03/20 Python
浅谈Python实现2种文件复制的方法
2018/01/19 Python
Python学习_几种存取xls/xlsx文件的方法总结
2018/05/03 Python
python binascii 进制转换实例
2019/06/12 Python
pytorch索引查找 index_select的例子
2019/08/18 Python
python中not、and和or的优先级与详细用法介绍
2020/11/03 Python
python 获取域名到期时间的方法步骤
2021/02/10 Python
python压包的概念及实例详解
2021/02/17 Python
基层工作经历证明
2014/01/13 职场文书
党员先锋岗事迹材料
2014/05/08 职场文书
依法行政工作汇报材料
2014/10/28 职场文书
2015年药店工作总结
2015/04/20 职场文书
python解决12306登录验证码的实现
2021/04/18 Python
Python Flask请求扩展与中间件相关知识总结
2021/06/11 Python
php将xml转化对象的实例详解
2021/11/17 PHP
苹果发布了MagSafe固件更新,可以不外接电源实现最高7.5W充电
2022/04/21 数码科技