首页 > 编程语言 >thinkphp3.2后台谷歌验证码

thinkphp3.2后台谷歌验证码

时间:2023-06-23 15:33:01浏览次数:43  
标签:return 谷歌 thinkphp3.2 验证码 secret base32chars str array NULL

1.谷歌类库

A
<?php

namespace Common\Ext;

class GoogleAuthenticator
{
	protected $_codeLength = 6;

	public function createSecret($secretLength = 16)
	{
		$validChars = $this->_getBase32LookupTable();
		unset($validChars[32]);
		$secret = '';
		$i = 0;

		for (; $i < $secretLength; $i++) {
			$secret .= $validChars[array_rand($validChars)];
		}

		return $secret;
	}

	public function getCode($secret, $timeSlice = NULL)
	{
		if ($timeSlice === null) {
			$timeSlice = floor(time() / 30);
		}

		$secretkey = $this->_base32Decode($secret);
		$time = chr(0) . chr(0) . chr(0) . chr(0) . pack('N*', $timeSlice);
		$hm = hash_hmac('SHA1', $time, $secretkey, true);
		$offset = ord(substr($hm, -1)) & 15;
		$hashpart = substr($hm, $offset, 4);
		$value = unpack('N', $hashpart);
		$value = $value[1];
		$value = $value & 2147483647;
		$modulo = pow(10, $this->_codeLength);
		return str_pad($value % $modulo, $this->_codeLength, '0', STR_PAD_LEFT);
	}

	public function getQRCodeGoogleUrl($name, $secret, $title = NULL)
	{
		return 'otpauth://totp/' . $name . '?secret=' . $secret;
	}

	public function verifyCode($secret, $code, $discrepancy = 1, $currentTimeSlice = NULL)
	{
		if ($currentTimeSlice === null) {
			$currentTimeSlice = floor(time() / 30);
		}

		// $i = -$discrepancy;
		$i = -$discrepancy-2;

		for (; $i <= $discrepancy; $i++) {
			$calculatedCode = $this->getCode($secret, $currentTimeSlice + $i);
			$cal .= '='.$calculatedCode;
			if ($calculatedCode == $code) {
				return true;
			}
		}

		return false;
	}

	public function setCodeLength($length)
	{
		$this->_codeLength = $length;
		return $this;
	}

	protected function _base32Decode($secret)
	{
		if (empty($secret)) {
			return '';
		}

		$base32chars = $this->_getBase32LookupTable();
		$base32charsFlipped = array_flip($base32chars);
		$paddingCharCount = substr_count($secret, $base32chars[32]);
		$allowedValues = array(6, 4, 3, 1, 0);

		if (!in_array($paddingCharCount, $allowedValues)) {
			return false;
		}

		$i = 0;

		for (; $i < 4; $i++) {
			if (($paddingCharCount == $allowedValues[$i]) && (substr($secret, -$allowedValues[$i]) != str_repeat($base32chars[32], $allowedValues[$i]))) {
				return false;
			}
		}

		$secret = str_replace('=', '', $secret);
		$secret = str_split($secret);
		$binaryString = '';
		$i = 0;

		for (; $i < count($secret); $i = $i + 8) {
			$x = '';

			if (!in_array($secret[$i], $base32chars)) {
				return false;
			}

			$j = 0;

			for (; $j < 8; $j++) {
				$x .= str_pad(base_convert(@($base32charsFlipped[@($secret[$i + $j])]), 10, 2), 5, '0', STR_PAD_LEFT);
			}

			$eightBits = str_split($x, 8);
			$z = 0;

			for (; $z < count($eightBits); $z++) {
				$binaryString .= (($y = chr(base_convert($eightBits[$z], 2, 10))) || (ord($y) == 48) ? $y : '');
			}
		}

		return $binaryString;
	}

	protected function _base32Encode($secret, $padding = true)
	{
		if (empty($secret)) {
			return '';
		}

		$base32chars = $this->_getBase32LookupTable();
		$secret = str_split($secret);
		$binaryString = '';
		$i = 0;

		for (; $i < count($secret); $i++) {
			$binaryString .= str_pad(base_convert(ord($secret[$i]), 10, 2), 8, '0', STR_PAD_LEFT);
		}

		$fiveBitBinaryArray = str_split($binaryString, 5);
		$base32 = '';
		$i = 0;

		while ($i < count($fiveBitBinaryArray)) {
			$base32 .= $base32chars[base_convert(str_pad($fiveBitBinaryArray[$i], 5, '0'), 2, 10)];
			$i++;
		}

		if ($padding && ($x = strlen($binaryString) % 40 != 0)) {
			if ($x == 8) {
				$base32 .= str_repeat($base32chars[32], 6);
			}
			else if ($x == 16) {
				$base32 .= str_repeat($base32chars[32], 4);
			}
			else if ($x == 24) {
				$base32 .= str_repeat($base32chars[32], 3);
			}
			else if ($x == 32) {
				$base32 .= $base32chars[32];
			}
		}

		return $base32;
	}

	protected function _getBase32LookupTable()
	{
		return array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7', '=');
	}
}

?>

2.谷歌HTML页面

A
<include file="Public:header"/>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>绑定谷歌二维码1</title>
    <!-- 引入qrcode.js库 -->
    <script type="text/javascript" src="/Public/Static/js/qrcode.js"></script>
    <style>
        body {
            position: relative;
            min-height: 100vh;
            margin: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            font-family: Arial, sans-serif;
            background-color: #f5f5f5;
        }

        .container {
            display: flex;
            flex-direction: column;
            align-items: center;
            text-align: center;
            background-color: #fff;
            padding: 20px;
            border-radius: 5px;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
        }

        .container p {
            margin: 10px 0;
            font-size: 18px;
            font-weight: bold;
        }

        #qrcode {
            width: 200px;
            height: 200px;
            margin-top: 20px;
        }

        .qr-instructions {
            margin-top: 20px;
            font-size: 16px;
            line-height: 1.5;
            color: #888;
        }

        .qr-instructions span {
            display: block;
            margin-bottom: 10px;
        }

        .qr-instructions strong {
            color: #333;
        }

        .avatar {
            position: absolute;
            bottom: 20px;
            right: 20px;
            width: 60px;
            height: 60px;
            background-image: url('/Public/Home/static/imgs/gg.jpg'); /* 替换为您上传的图片路径 */
            background-size: cover;
            background-position: center;
            background-repeat: no-repeat;
            border-radius: 50%;
        }
    </style>

</head>

<body>
<div class="container">
    <div>
        <p>身份验证</p>
        <div class="qr-instructions">
            <span>1. 在移动设备上安装验证器应用</span>
            <span>2. 在验证器应用中扫描以下二维码</span>
        </div>
    </div>
    <!-- 在页面中创建一个容器用于显示二维码 -->
    <div id="qrcode"></div>
    <div class="avatar">
    </div>
</div>

<!-- 在JavaScript中生成二维码 -->
<script>
    // 获取二维码文本数据
    var qrCodeText = "{$qrCodeUrl}";

    // 创建二维码实例
    var qrcode = new QRCode(document.getElementById("qrcode"), {
        render: "canvas",
        text: qrCodeText,
        width: 200,
        height: 200,
        correctLevel : QRCode.CorrectLevel.H
    });

</script>
<include file="Public:footer"/>
<block name="script">
    <script type="text/javascript" charset="utf-8">
        //导航高亮
        highlight_subnav("{:U('User/orcode')}");
    </script>
</block>

2.1登录页面加

<!--输入谷歌验证码-->
		<div class="form-group">
			<div class="inputs" style="width:100%; background:#f5f5f5;border: 1px solid #f5f5f5f5;">
				<i class="icon-login-google"></i>
				<input type="text" name="google_verify" autocomplete="off" placeholder="谷歌验证码" id="google_verify" style="width:75%;background:#f5f5f5;color:#000;">
			</div>
			<div class="imgcode">
				<a href="http://jys.gg/Admin/Login/orcode"></a>
			</div>
			
		</div>

3.控制器

<?php
namespace Admin\Controller;

use Common\Ext\GoogleAuthenticator;

class UserController extends AdminController
{
    public function adminGroup($id)
    {
            if (empty($id)) {
                $this->data = null;
            } else {
                $data = array(
                    'uid' => trim($id),
                    'group_id' => 1,
                );
                M('auth_group_access')->add($data);
                $result = M("admin")->where(array('id'=>$id))->save(array('is_group'=>1));
                if ($result) {
                    // 新增成功
                    $this->success("成功");
                } else {
                    // 新增失败
                    $this->success("失败");
                }
            }

    }

    //  谷歌验证码绑定
    public function orcode($username = NULL)
    {
        $username = session('admin_username');

        // 当前管理员的信息
        $info = M('Admin')->where(array('username' => $username))->find();
        $ga = new GoogleAuthenticator();

        // 生成密钥
        $secret = $ga->createSecret();

        // 生成二维码链接
        $qrCodeUrl = $ga->getQRCodeGoogleUrl($username, $secret);

        if ($info['google'] == '22222222222'){
            $this->ajaxReturn(['code'=>100,'msg'=>'请勿重复绑定!']);
        }else{
            if ($info['google'] == '1')
            {
                // 将秘钥保存到数据库
                $data = array(
                    'secret' => $secret,
                    //绑定谷歌  1:未绑定 2:已绑定
                    'google' => '2'
                );
                $where = array(
                    'id' => $info['id'],
                );
                M('Admin')->where($where)->save($data);
            }
        }

        $this->assign('qrCodeUrl', $qrCodeUrl);
        $this->display();
    }		
}
?>

3.1控制器验证谷歌码

$admin = M('Admin')->where(array('username' => $username))->find();
            if($admin['google'] == '2')
            {
                // 验证谷歌验证码
                $googleCode = $_POST['google_verify'];
                $authenticator = new GoogleAuthenticator();
                if (!$authenticator->verifyCode($admin['secret'], $googleCode)) {
                    $this->error('谷歌验证码错误');
                }
            }

4.数据库admin表

CREATE TABLE `tw_admin` (
	`id` INT ( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT,
	`email` VARCHAR ( 200 ) NOT NULL DEFAULT '',
	`username` CHAR ( 16 ) NOT NULL,
	`nickname` VARCHAR ( 50 ) NOT NULL,
	`moble` VARCHAR ( 50 ) NOT NULL,
	`password` CHAR ( 32 ) NOT NULL,
	`mass_hair` INT ( 1 ) DEFAULT '0' COMMENT '是否开启群发功能0: 关闭 |1:开启 ',
	`sort` INT ( 11 ) UNSIGNED NOT NULL,
	`addtime` INT ( 11 ) UNSIGNED NOT NULL,
	`last_login_time` INT ( 11 ) UNSIGNED NOT NULL,
	`last_login_ip` INT ( 11 ) UNSIGNED NOT NULL,
	`endtime` INT ( 11 ) UNSIGNED NOT NULL,
	`status` INT ( 4 ) NOT NULL,
	`secret` VARCHAR ( 50 ) CHARACTER 
	SET utf8 COLLATE utf8_bin NOT NULL COMMENT '谷歌秘钥',
	`google` INT ( 4 ) NOT NULL DEFAULT '1' COMMENT '绑定谷歌  1:未绑定 2:已绑定',
	`is_group` INT ( 1 ) NOT NULL DEFAULT '0' COMMENT '是否绑定了分组 未绑定0 已绑定1',
	PRIMARY KEY ( `id` ) USING BTREE,
	KEY `status` ( `status` ) USING BTREE,
KEY `username` ( `username` ) USING BTREE 
) ENGINE = MyISAM AUTO_INCREMENT = 10 DEFAULT CHARSET = utf8 ROW_FORMAT = DYNAMIC COMMENT = '管理员表';

5.完成

thinkphp3.2后台谷歌验证码_验证码

标签:return,谷歌,thinkphp3.2,验证码,secret,base32chars,str,array,NULL
From: https://blog.51cto.com/u_15901780/6538118

相关文章

  • thinkphp3.2评论回复点赞功能
    1.composer下载thinkphp3.2composercreate-projecttopthink/thinkphpyour-project-name2.创建数据库CREATETABLE`comments`( `id`INT(11)UNSIGNEDNOTNULLAUTO_INCREMENT, `content`textCOLLATEutf8_unicode_ciNOTNULL, `user_id`INT(11)UNSIGNEDNOTNU......
  • PaLM 2全面反超反超GPT-4,谷歌官宣AI重构搜索,朝着ChatGPT微软开炮
    现在,谷歌搜索终于要加入AI对话功能了,排队通道已经开放。当然这还只是第一步。大的还在后面:全新大语言模型PaLM2正式亮相,谷歌声称它在部分任务超越GPT-4。Bard能力大更新,不用再排队等候,并支持新语言。谷歌版AI办公助手也一并推出,将在Gmail中抢先亮相。谷歌云也上线多个基础大模型,为......
  • TienChin 验证码响应结果分析&验证码生成接口分析
    验证码响应结果分析首先从前端开始进行分析,进入到登录页面,打开开发者工具(f12),找到network,f5刷新一下页面,然后,筛选一下,筛选内容为Fetch/XHR:你会发现列表中有两项内容,我们只需要查看captchaImage即可,从名字就可以看出是验证码图片的意思,然后我们查看这个响应结果是什么,响应......
  • go 使用验证码库
    go使用验证码库标签(空格分隔):go安装gogetgithub.com/mojocn/base64Captcha使用packageapiimport( "github.com/gin-gonic/gin" "github.com/mojocn/base64Captcha" "go.uber.org/zap" "net/http")var( //存储方式 store=base......
  • 谷歌RoboCat:能解决和适应多种任务的机器人AI智能体
    刚刚,谷歌DeepMind推出了一种可以自我改进、自我提升(self-improving)的用于机器人的AI智能体,名为“RoboCat”。DeepMind称它是全球第一个可以解决和适应多种任务的机器人AI智能体,并且它可以在各类真实的机器人产品上完成这些任务。▲RoboCat操控机械臂完成各种各样的任务,来源:Goog......
  • IDEA 取消右上角 Firefox(火狐)、Chrome(谷歌)、Edge的图标一直闪烁!
     IDEA 取消右上角Firefox(火狐)、Chrome(谷歌)、Edge的图标一直闪烁,File>Settings>Tools>WebBrowsersandPreview,去掉三个浏览器的对勾即可! ......
  • PostgreSQL 新闻速递 谷歌基于POSTGRESQL 兼容数据库提供更大规模的数据库服务
    开头还是介绍一下群,如果感兴趣polardb,mongodb,mysql,postgresql ,redis等有问题,有需求都可以加群群内有各大数据库行业大咖,CTO,可以解决你的问题。谷歌正在将针对PostgreSQL的AlloyDB数据库服务扩展至16个新区域。AlloyDB是一个兼容PostgreSQL的托管数据库服务,于去年......
  • 网安--在谷歌浏览器中安装插件
    1、在https://crxdl.com/中先下载插件包2、有两种方法第一种可以将下载下来的安装包解压出来的crx文件直接拖入这个页面,但是会出现报错 如果报错使用第二种方法将解压后的crx文件先压缩(改名字并且后缀改为zip)再解压 在这里将解压后的文件加入扩展程序 ......
  • 手机验证码登录
    代码写在reggie_take_out5中了从这里就到了移动端开发1. 效果展示  5-122. 短信发送  5-132.1 短信服务介绍  5-13目前市面.上有很多第三方提供的短信服务,这些第三方短信服务会和各个运营商(移动、联通、电信)对接,我们只需要注册成为会员并且按照提供的开发文档进行调用就......
  • 快速入门|Flutter完整开发实战详解 谷歌架构师独家分享
    前言这几年在大前端的开发领域,选择跨端方案的公司和部门越来越多,一方面是跨平台的前端框架越来越成熟,另一方面也是因原生开发者正逐年减少。所以,在当下掌握一门跨平台的技术栈还是很有必要的,无论从广度还是从深度都会有所帮助。就目前来说有很多主流的跨平台框架,就比如:Flutter、Rea......