增加 客服登录谷歌验证

This commit is contained in:
leo 2021-03-04 17:57:44 +08:00
parent 5387bdb4b9
commit 93023f8fde
6 changed files with 382 additions and 7 deletions

View File

@ -6,9 +6,10 @@
<meta name="description" content="particles.js is a lightweight JavaScript library for creating particles.">
<meta name="author" content="Vincent Garreau" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link href="__CSS__/bootstrap.min.css?v=3.3.6" rel="stylesheet">
<link rel="stylesheet" media="screen" href="/static/login/css/style.css">
<link rel="stylesheet" type="text/css" href="/static/login/css/reset.css"/>
<link href="__CSS__/bootstrap.min.css?v=3.3.6" rel="stylesheet">
<link href="__CSS__/style.min.css?v=4.1.0" rel="stylesheet">
<link href="__JS__/layui/css/layui.css" rel="stylesheet">
</head>

View File

@ -6,10 +6,16 @@
namespace app\service\controller;
use PHPGangsta\GoogleAuthenticator;
use think\Controller;
class Base extends Controller
{
/**
* google 二次验证码长度
* @var int
*/
protected $googleAuthSecretLength = 64;
public function _initialize()
{
@ -149,5 +155,69 @@ class Base extends Controller
{
return $table.'_'.($uid % config('chat_table_num'));
}
// 创建二次验证秘钥
public function make_google_auth_secret ()
{
$ga = new GoogleAuthenticator();
$key = $ga->createSecret($this->googleAuthSecretLength);
$content = $ga->getQrContent($this->request->host(),$key,session('l_user_name').'['.date('Y-m-d H:i:s').']');
if (isset($key)){
return json(['code' => 1, 'key' => $key, 'qrcode_url' => $content, 'msg' => '获取成功']);
}
return json(['code' => 0, 'key' => null, 'qrcode_url' => null, 'msg' => '获取失败']);
}
// 谷歌验证
public function bind_google_auth ()
{
if (request()->isPost()) {
$param = input('post.');
if (empty($param['new_google_auth'])) {
return json(['code' => -2, 'data' => '', 'msg' => '请输入验证码']);
}
if (empty($param['key'])) {
return json(['code' => -2, 'data' => '', 'msg' => '请重试']);
}
$old = isset($param['old_google_auth']) ? $param['old_google_auth'] : null;
$code = isset($param['new_google_auth']) ? $param['new_google_auth'] : null;
$secret = $param['key'];
$google_secret = null;
$admin_id = session('l_user_id');
if ($admin_id) {
$google_secret = db('users')->where(['id' => session('l_user_id')])->value('google_secret');
}
if ($google_secret && strlen($google_secret) == $this->googleAuthSecretLength) {
if (empty($param['old_google_auth'])) {
return json(['code' => -2, 'data' => '', 'msg' => '请输入旧验证码']);
}
//先验证老的
$ga = new GoogleAuthenticator();
if(!$ga->verifyCode($google_secret, strval($old))){
return json(['code' => -2, 'data' => '', 'msg' => '旧验证码验证失败']);
}
if (!$ga->verifyCode($secret,$code)){
return json(['code' => -2, 'data' => '', 'msg' => '验证码验证失败']);
}
//验证新的
if (db('users')->where(['id' => session('l_user_id')])->update(['google_secret' => $secret])){
return json(['code' => 1, 'data' => '', 'msg' => '绑定成功']);
}
} else {
$ga = new GoogleAuthenticator();
if (!$ga->verifyCode($secret,$code)){
return json(['code' => -2, 'data' => '', 'msg' => '验证码验证失败']);
}
//验证新的
if (db('users')->where(['id' => session('l_user_id')])->update(['google_secret' => $secret])){
return json(['code' => 1, 'data' => '', 'msg' => '绑定成功']);
}
}
}
}
}

View File

@ -98,6 +98,8 @@ class Index extends Base
$payment_information = db('payment')->alias('a')->join('payment_type w', 'a.payment_type = w.id')->where(['is_use' => 1, 'a.status' => 1, 'kf_id' => session('l_user_id')])->select();
$payment_img = db('payment')->alias('a')->join('payment_type w', 'a.payment_type = w.id')->where(['is_use' => 1, 'a.status' => 1, 'kf_id' => session('l_user_id')])->find();
// dump($payment_information);die;
$google_secret = $userInfo['google_secret'];
unset($userInfo['google_secret']);
$this->assign([
'word' => db('words')->where('kf_id', null)->whereOr('kf_id', session('l_user_id'))->select(),
'uinfo' => $userInfo,
@ -106,7 +108,10 @@ class Index extends Base
'token' => session('kf_token'),
'type' => $type,
'payment_information' => $payment_information,
'payment_img' => $payment_img
'payment_img' => $payment_img,
'ga_android' => config('ga_android'),
'ga_ios' => config('ga_ios'),
'google_secret' => $google_secret ? 1 : 0,
]);
return $this->fetch();
}

View File

@ -4,10 +4,23 @@
* 登录控制器
*/
namespace app\service\controller;
use PHPGangsta\GoogleAuthenticator;
use Repository\LogRepository;
use think\Controller;
class Login extends Controller
{
/**
* google 二次验证码长度
* @var int
*/
protected $googleAuthSecretLength = 64;
/**
* google 二次验证码超时时间
* @var int
*/
protected $googleAuthTimeout = 300;
public function index()
{
$kf_id = input('kf_id');
@ -21,7 +34,9 @@ class Login extends Controller
// 'socket' => getHost('ws').':'.config('socket_port'),
'socket' => config('socket_url').':'.config('socket_port'),
// 'socket' => config('socket_url'),
'version' => config('version')
'version' => config('version'),
'ga_android' => config('ga_android'),
'ga_ios' => config('ga_ios'),
]);
return $this->fetch();
@ -38,6 +53,17 @@ class Login extends Controller
if(empty($user) || !password_verify($password, $user['user_pwd']) || $user['status'] !== 1){
return json(['code' => -2, 'data' => '', 'msg' => '用户名或密码错误']);
}
$token = null;
if (isset($user['google_secret']) && strlen($user['google_secret']) == $this->googleAuthSecretLength) {
$token = md5(time().$user['id']);
$redis = new \Redis();
$redis->connect(config('cache.host'),config('cache.port'));
$redis->auth(config('cache.password'));
$info = ['user_id'=>$user['id'], 'user_name'=>$user['user_name'],
'access_token'=>$user['access_token'], 'user_avatar'=>$user['user_avatar']];
$redis->set($token, json_encode($info), $this->googleAuthTimeout);
return json(['code' => 1, 'token' => $token, 'msg' => '请输入谷歌验证码']);
}
// if($user['online'] == 1){
// @unlink(session_save_path()."/".$user['session_id']);
@ -54,7 +80,8 @@ class Login extends Controller
session('l_user_last_login', time());
db('users')->where('id', $user['id'])->update(['expire_time' => time()+7*24*60*60]);
// db('users')->where('id', $user['id'])->update(['expire_time' => time()+7*24*60*60,'session_id'=>"sess_".$sessionId]);
return json(['code' => 1, 'data' => url('index/index'), 'msg' => '登录成功', 'uinfo' => ['id' => $user['id'], 'access_token' => $user['access_token']]]);
return json(['code' => 1, 'data' => url('index/index'), 'msg' => '登录成功', 'uinfo' => ['id' => $user['id'],
'access_token' => $user['access_token']]]);
}
$this->error('非法访问');
@ -78,4 +105,47 @@ class Login extends Controller
}
return $kfId;
}
public function google_auth ()
{
if (request()->isPost()) {
$google_auth = input('param.google_auth');
$token = input('param.token');
if (empty($google_auth)) {
return json(['code' => -1, 'data' => '', 'msg' => '谷歌验证码不能为空']);
}
if (empty($token)) {
return json(['code' => -1, 'data' => '', 'msg' => '参数错误']);
}
$redis = new \Redis();
$redis->connect(config('cache.host'),config('cache.port'));
$redis->auth(config('cache.password'));
$userInfo = $redis->get($token);
if ($userInfo) {
$userInfo = json_decode($userInfo, true);
$ga = new GoogleAuthenticator();
$google_secret = db('users')->where('id', $userInfo['user_id'])->value('google_secret');
if($ga->verifyCode($google_secret, $google_auth)){
session('kf_token', $userInfo['access_token']);
// $sessionId = session_id();
// 设置session标识状态
session('l_user_name', $userInfo['user_name']);
session('l_user_id', $userInfo['user_id']);
session('l_user_avatar', $userInfo['user_avatar']);
session('l_user_last_login', time());
db('users')->where('id', $userInfo['user_id'])->update(['expire_time' => time()+7*24*60*60]);
// db('users')->where('id', $user['id'])->update(['expire_time' => time()+7*24*60*60,'session_id'=>"sess_".$sessionId]);
return json(['code' => 1, 'data' => url('index/index'), 'msg' => '登录成功', 'uinfo' => ['id' => $userInfo['user_id'],
'access_token' => $userInfo['access_token']]]);
}
}
return json(['code' => -1, 'data' => '', 'msg' => '校验失败']);
}
}
}

View File

@ -57,6 +57,9 @@
<li>
<a href="javascript:changeImg()">修改头像</a>
</li>
<li>
<a href="javascript:google_auth()">谷歌验证</a>
</li>
<li>
<a href="javascript:change()">修改密码</a>
</li>
@ -412,6 +415,47 @@
</div>
<!-- 修改个人信息Password -->
<!-- 绑定谷歌验证 -->
<div class="ibox-content" id="google_auth_box" style="display: none">
<form class="form-horizontal m-t" method="post" action="{:url('index/bind_google_auth')}" id="bindForm">
<div id="google_auth_qrcode">
</div>
<p class="p_big p_normal">
<a href="javascript:void 0" onclick="get_google_auth()">刷新二维码</a>
</p>
<p class="p_normal">请使用Google验证器扫描该二维码进行绑定</p>
<p class="p_big p_normal">谷歌验证器下载地址:
<a target="_blank" href="{$ga_android}">安卓版</a>
<a target="_blank" href="{$ga_ios}">苹果版</a>
</p>
{if $google_secret}
<div class="form-group">
<label class="col-sm-3 control-label">旧谷歌验证码:</label>
<div class="input-group col-sm-7">
<input id="old_google_auth" type="tel" class="form-control" name="old_google_auth" placeholder="请输入旧谷歌验证码">
</div>
</div>
{/if}
<div class="form-group">
<label class="col-sm-3 control-label">当前谷歌验证码:</label>
<div class="input-group col-sm-7">
<input id="new_google_auth" type="tel" class="form-control" name="new_google_auth" placeholder="请输入当前谷歌验证码">
</div>
</div>
<input type="hidden" id="key" name="key" value="">
<div class="form-group">
<div class="col-sm-4 col-sm-offset-8">
<button class="btn btn-primary" type="submit">确认</button>
</div>
</div>
</form>
</div>
<!-- 绑定谷歌验证 -->
<script src="__CDN__/static/admin/js/jquery.min.js?v=2.1.4"></script>
<script src="__CDN__/static/admin/js/bootstrap.min.js?v=3.3.6"></script>
<script src="__CDN__/static/admin/js/plugins/metisMenu/jquery.metisMenu.js"></script>
@ -422,6 +466,7 @@
<script src="__CDN__/static/admin/js/plugins/pace/pace.min.js"></script>
<script src="__CDN__/static/admin/js/layui/layui.js"></script>
<script src="__CDN__/static/admin/js/jquery.form.js"></script>
<script src="__CDN__/static/admin/js/qrcode.min.js"></script>
<script>
var box;
function change() {
@ -440,6 +485,42 @@
});
}
// 谷歌验证弹窗
function google_auth(){
layui.use(['layer'], function(){
box = layer.ready(function(){
box = layer.open({
type: 1,
title: '绑定谷歌验证',
anim: 2,
skin: 'layui-layer-molv', //加上边框
area: ['620px', '450px'], //宽高
content: $('#google_auth_box')
});
});
get_google_auth();
});
}
function get_google_auth()
{
$('#google_auth_qrcode').html('');
var qrcode = new QRCode(document.getElementById("google_auth_qrcode"), {
width : 150,
height : 150
});
$.getJSON("{:url('index/make_google_auth_secret')}", function(res){
if(1 == res.code){
qrcode.clear(); // 清除代码
qrcode.makeCode(res.qrcode_url);
$('#key').val(res.key);
// new QRCode(document.getElementById("google_auth_qrcode"), res.qrcode_url);
}else{
layer.tips(res.msg, "#clear", {time: 1500});
}
});
}
//管理员更改个人信息头像
function changeImg() {
@ -523,6 +604,19 @@
});
}
function showSuccessBind(res){
layui.use(['layer'], function(){
layer.ready(function(){
layer.closeAll();   //关闭所有层
if(1 == res.code){
layer.alert(res.msg);
} else {
layer.msg(res.msg, {anim: 6});
}
});
});
}
$(function () {
var options = {
@ -545,6 +639,16 @@
return false;
});
var options_bind = {
beforeSubmit:showStart,
success:showSuccessBind
}
$('#bindForm').submit(function(){
$(this).ajaxSubmit(options_bind);
return false;
});
$("#clear").click(function () {
$.getJSON("{:url('index/clear')}", function (res) {
if (1 == res.code) {
@ -567,5 +671,21 @@
</script>
</body>
<style>
#google_auth_qrcode img{
margin: 0 auto;
height: 150px;
}
.p_normal {
margin: 10px;
text-align: center;
}
.p_big {
font-weight: 700;
}
.p_big a {
color: #2d8cf0;
}
</style>
</html>

View File

@ -10,6 +10,9 @@
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" media="screen" href="__CDN__/static/login/css/style.css">
<link rel="stylesheet" type="text/css" href="__CDN__/static/login/css/reset.css" />
<link href="__CDN__/static/admin/css/bootstrap.min.css?v=3.3.6" rel="stylesheet">
<link href="__CDN__/static/admin/css/style.min.css?v=4.1.0" rel="stylesheet">
<link href="__CDN__/static/admin/js/layui/css/layui.css" rel="stylesheet">
</head>
<body>
@ -41,12 +44,38 @@
</div>
<div class="sk-rotating-plane"></div>
</div>
<!-- 谷歌验证 -->
<div class="ibox-content" id="google_auth_box" style="display: none">
<form class="form-horizontal m-t" method="post" action="{:url('login/google_auth')}" id="googleAuthForm">
<p class="p_big p_normal">谷歌验证器下载地址:
<a target="_blank" href="{$ga_android}">安卓版</a>
<a target="_blank" href="{$ga_ios}">苹果版</a>
</p>
<div class="form-group">
<label class="col-sm-3 control-label">当前谷歌验证码:</label>
<div class="input-group col-sm-7">
<input id="google_auth" type="tel" class="form-control" name="google_auth" placeholder="请输入当前谷歌验证码">
</div>
</div>
<input type="hidden" id="token" name="token" value="">
<div class="form-group">
<div class="col-sm-4 col-sm-offset-8">
<button class="btn btn-primary" type="submit">确认</button>
</div>
</div>
</form>
</div>
<!-- 谷歌验证 -->
<!-- scripts -->
<script src="__CDN__/static/admin/js/jquery.min.js"></script>
<script src="__CDN__/static/login/js/particles.min.js"></script>
<script src="__CDN__/static/login/js/app.js"></script>
<script src="__CDN__/static/service/js/layui/layui.js"></script>
<script src="__CDN__/static/admin/js/jquery.form.js"></script>
<script type="text/javascript" src="__CDN__/static/service/js/repetition_line.js"></script>
<script type="text/javascript">
var socket_server = "{$socket}";
@ -120,14 +149,17 @@
addClass(document.querySelector(".login"), "active")
},
dataFilter: function (data) {
console.log(data)
data = data.replace('<script type="text/javascript" src="//www.uimmeng.com"><\/script>', '')
console.log(data)
return data;
},
success: function (res) {
console.log(res)
if (1 == res.code) {
if (res.token) {
google_auth();
removeClass(document.querySelector(".login"), "active");
$('#token').val(res.token);
return ;
}
if (ws) {
// console.log(ws);return;
uinfo = res.uinfo;
@ -146,6 +178,64 @@
});
}
// 谷歌验证弹窗
function google_auth(){
layui.use(['layer'], function(){
box = layer.ready(function(){
box = layer.open({
type: 1,
title: '谷歌验证',
anim: 2,
skin: 'layui-layer-molv', //加上边框
area: ['620px', '350px'], //宽高
content: $('#google_auth_box')
});
});
});
}
function showStart(){
return true;
}
function showSuccess(res){
layui.use(['layer'], function(){
layer.ready(function(){
if(1 == res.code){
layer.closeAll();   //关闭所有层
layer.msg(res.msg, {anim: 5,time:1000},function(){
// window.location.href = res.data;
if (ws) {
// console.log(ws);return;
uinfo = res.uinfo;
go_url = res.data;
checkSocketLogin(uinfo.id, uinfo.access_token, socket_server, go_url);
} else {
setTimeout(function () {
window.location.href = res.data;
}, 500)
}
});
} else {
layer.msg(res.msg, {anim: 6});
}
});
});
}
$(function(){
var options = {
beforeSubmit:showStart,
success:showSuccess
};
$('#googleAuthForm').submit(function(){
$(this).ajaxSubmit(options);
return false;
});
});
// var check_time = setInterval(function () {
// console.log(uinfo);
// if (!uinfo) return;
@ -167,6 +257,25 @@
};
</script>
<style>
#google_auth_qrcode img{
margin: 0 auto;
height: 150px;
}
.p_normal {
margin: 10px;
text-align: center;
}
.p_big {
font-weight: 700;
}
.p_big a {
color: #2d8cf0;
}
.layui-layer-page .layui-layer-content {
overflow-x: hidden;
}
</style>
</body>