实现微信扫码登陆

This commit is contained in:
云泽网 2025-06-06 22:36:53 +08:00
parent 25b765517a
commit 6f30eedf4a
3 changed files with 225 additions and 145 deletions

View File

@ -70,10 +70,10 @@ abstract class BaseController
$userInfo = []; $userInfo = [];
if (session('user_id')) { if (session('user_id')) {
// 从数据库获取最新用户信息 // 从数据库获取最新用户信息
$user = Users::where('id', session('user_id'))->find(); $user = Users::where('uid', session('user_id'))->find();
if ($user) { if ($user) {
$userInfo = [ $userInfo = [
'id' => $user->id, 'id' => $user->uid,
'name' => $user->name, 'name' => $user->name,
'account' => $user->account, 'account' => $user->account,
'avatar' => $user->avatar ?? '/static/images/avatar.png', 'avatar' => $user->avatar ?? '/static/images/avatar.png',

View File

@ -5,7 +5,7 @@ use think\facade\Request;
use think\facade\Log; use think\facade\Log;
use think\facade\Cache; use think\facade\Cache;
use GuzzleHttp\Client; use GuzzleHttp\Client;
use app\index\model\User; use app\index\model\Users;
use app\index\model\AdminConfig; use app\index\model\AdminConfig;
class WechatController extends BaseController class WechatController extends BaseController
@ -196,8 +196,11 @@ class WechatController extends BaseController
$postStr = mb_convert_encoding($postStr, 'UTF-8', 'UTF-8,GBK,GB2312'); $postStr = mb_convert_encoding($postStr, 'UTF-8', 'UTF-8,GBK,GB2312');
Log::info('微信消息原始数据:' . $postStr); Log::info('微信消息原始数据:' . $postStr);
libxml_disable_entity_loader(true); // 使用DOMDocument替代simplexml_load_string
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA); $dom = new \DOMDocument();
$dom->loadXML($postStr, LIBXML_NOCDATA | LIBXML_NOBLANKS);
$postObj = simplexml_import_dom($dom);
if ($postObj === false) { if ($postObj === false) {
Log::error('微信消息XML解析失败'); Log::error('微信消息XML解析失败');
return ''; return '';
@ -278,47 +281,112 @@ class WechatController extends BaseController
if (isset($userInfo['openid'])) { if (isset($userInfo['openid'])) {
// 保存用户信息到数据库 // 保存用户信息到数据库
$user = User::where('openid', $fromUsername)->find(); $user = Users::where('openid', $fromUsername)->find();
if (!$user) { if (!$user) {
$user = new User; $user = new Users;
$user->openid = $fromUsername; $user->openid = $fromUsername;
$user->name = $userInfo['nickname'] ?? ''; // 生成默认账号
$user->avatar = $userInfo['headimgurl'] ?? ''; $defaultAccount = 'wx_' . substr(md5($fromUsername), 0, 8);
$user->save(); $user->account = $defaultAccount;
Log::info('创建新用户成功', ['user' => $user->toArray()]); $user->name = $defaultAccount; // 将默认账号同时设置为用户名
// 设置头像,确保有值
$user->avatar = !empty($userInfo['headimgurl']) ? $userInfo['headimgurl'] : '/static/images/avatar.png';
// 生成随机密码
$user->password = md5(uniqid() . rand(1000, 9999));
$user->create_time = time(); // 设置创建时间
$user->login_count = 1; // 首次登录设置登录次数为1
if (!$user->save()) {
Log::error('创建用户失败:' . json_encode($user->getError(), JSON_UNESCAPED_UNICODE));
return 'success';
}
// 重新获取用户信息以确保获取到uid
$user = Users::where('openid', $fromUsername)->find();
if (!$user) {
Log::error('获取新创建的用户信息失败');
return 'success';
}
Log::info('创建新用户成功:' . json_encode($user->toArray(), JSON_UNESCAPED_UNICODE));
} else { } else {
// 更新用户信息 // 更新用户信息
$user->name = $userInfo['nickname'] ?? $user->name; $needUpdate = false;
$user->avatar = $userInfo['headimgurl'] ?? $user->avatar;
$user->save(); // 只在用户名为空时设置
Log::info('更新用户信息成功', ['user' => $user->toArray()]); if (empty($user->name)) {
$user->name = $user->account;
$needUpdate = true;
}
// 只在头像为空或为默认头像时更新
if (empty($user->avatar) || $user->avatar === '/static/images/avatar.png') {
if (!empty($userInfo['headimgurl'])) {
$user->avatar = $userInfo['headimgurl'];
$needUpdate = true;
} elseif (empty($user->avatar)) {
$user->avatar = '/static/images/avatar.png';
$needUpdate = true;
}
}
// 增加登录次数
$user->login_count = $user->login_count + 1;
$needUpdate = true;
// 只在需要更新时才更新时间戳
if ($needUpdate) {
$user->update_time = time();
if (!$user->save()) {
Log::error('更新用户信息失败:' . json_encode($user->getError(), JSON_UNESCAPED_UNICODE));
return 'success';
}
Log::info('更新用户信息成功:' . json_encode($user->toArray(), JSON_UNESCAPED_UNICODE));
}
} }
// 更新票据文件 // 更新票据文件
$data['user_info'] = [ $data = [
'uid' => $user->uid, 'uid' => (int)$user->uid, // 确保uid是整数
'name' => $user->name, 'name' => $user->name,
'avatar' => $user->avatar, 'avatar' => $user->avatar ?: '/static/images/avatar.png', // 确保avatar不为空
'openid' => $user->openid 'openid' => $user->openid,
'user_account' => $user->account,
'user_password' => $user->password,
'expire_time' => time() + (7 * 24 * 3600), // 7天过期
'is_auto_login' => true,
'login_status' => 'success'
]; ];
$data['login_status'] = 'success';
if (file_put_contents($file, json_encode($data, JSON_UNESCAPED_UNICODE)) === false) { if (file_put_contents($file, json_encode($data, JSON_UNESCAPED_UNICODE)) === false) {
Log::error('更新票据文件失败:' . $file); Log::error('更新票据文件失败:' . $file);
} else { } else {
Log::info('更新票据文件成功'); Log::info('更新票据文件成功' . json_encode($data, JSON_UNESCAPED_UNICODE));
} }
// 设置登录session // 设置登录session
session('user_id', $user->uid); session('user_id', (int)$user->uid); // 确保session中的uid是整数
session('user_info', $data['user_info']); session('user_name', $user->name);
session('user_avatar', $user->avatar ?: '/static/images/avatar.png');
session('user_account', $user->account);
session('openid', $user->openid); session('openid', $user->openid);
// 设置cookie
$expire = 7 * 24 * 3600; // 7天过期
cookie('user_account', $user->account, ['expire' => $expire]);
cookie('user_avatar', $user->avatar ?: '/static/images/avatar.png', ['expire' => $expire]);
cookie('user_name', $user->name, ['expire' => $expire]);
cookie('open_id', $user->openid, ['expire' => $expire]);
Log::info('用户登录成功', [ Log::info('用户登录成功' . json_encode([
'uid' => $user->uid, 'uid' => (int)$user->uid,
'name' => $user->name, 'name' => $user->name,
'openid' => $user->openid 'openid' => $user->openid,
]); 'account' => $user->account,
'cookies' => [
'user_account' => $user->account,
'user_avatar' => $user->avatar,
'user_name' => $user->name,
'open_id' => $user->openid
]
], JSON_UNESCAPED_UNICODE));
} else { } else {
Log::error('获取用户信息失败:' . json_encode($userInfo, JSON_UNESCAPED_UNICODE)); Log::error('获取用户信息失败:' . json_encode($userInfo, JSON_UNESCAPED_UNICODE));
} }
@ -603,20 +671,17 @@ class WechatController extends BaseController
return json(['code' => 0, 'msg' => '等待扫码']); return json(['code' => 0, 'msg' => '等待扫码']);
} }
// 检查是否已经获取用户信息
if (!isset($loginData['user_info'])) {
return json(['code' => 0, 'msg' => '正在获取用户信息,请稍候...']);
}
// 检查登录状态 // 检查登录状态
if (!isset($loginData['login_status']) || $loginData['login_status'] !== 'success') { if (!isset($loginData['login_status']) || $loginData['login_status'] !== 'success') {
return json(['code' => 0, 'msg' => '正在处理登录,请稍候...']); return json(['code' => 0, 'msg' => '正在处理登录,请稍候...']);
} }
// 登录成功设置session // 登录成功设置session
session('user_id', $loginData['user_info']['uid']); session('user_id', $loginData['uid']);
session('user_info', $loginData['user_info']); session('user_name', $loginData['name']);
session('openid', $loginData['user_info']['openid']); session('user_avatar', $loginData['avatar']);
session('user_account', $loginData['user_account']);
session('openid', $loginData['openid']);
// 删除临时文件 // 删除临时文件
@unlink($file); @unlink($file);
@ -626,7 +691,14 @@ class WechatController extends BaseController
'code' => 1, 'code' => 1,
'msg' => '登录成功', 'msg' => '登录成功',
'data' => [ 'data' => [
'user_info' => $loginData['user_info'] 'uid' => $loginData['uid'],
'name' => $loginData['name'],
'avatar' => $loginData['avatar'],
'openid' => $loginData['openid'],
'user_account' => $loginData['user_account'],
'user_password' => $loginData['user_password'],
'expire_time' => $loginData['expire_time'],
'is_auto_login' => $loginData['is_auto_login']
] ]
]); ]);
@ -646,7 +718,7 @@ class WechatController extends BaseController
try { try {
// 这里需要根据你的用户表结构来实现 // 这里需要根据你的用户表结构来实现
// 示例从用户表中查询openid对应的用户信息 // 示例从用户表中查询openid对应的用户信息
$user = User::where('openid', $openid)->find(); $user = Users::where('openid', $openid)->find();
if ($user) { if ($user) {
return $user->toArray(); return $user->toArray();
} }

View File

@ -207,12 +207,12 @@
</div> </div>
<div class="layui-tab"> <div class="layui-tab">
<ul class="layui-tab-title"> <ul class="layui-tab-title">
<li class="layui-this" lay-id="account">账密登录</li> <li lay-id="account">账密登录</li>
<!-- <li lay-id="phone">手机验证码</li> --> <!-- <li lay-id="phone">手机验证码</li> -->
<li lay-id="wechat">微信登录</li> <li class="layui-this" lay-id="wechat">微信登录</li>
</ul> </ul>
<div class="layui-tab-content"> <div class="layui-tab-content">
<div class="layui-tab-item layui-show" id="account"> <div class="layui-tab-item" id="account">
<form action="#" method="post" class="layui-form login-form"> <form action="#" method="post" class="layui-form login-form">
<div class="layui-form-item"> <div class="layui-form-item">
<div class="layui-input-block" style="margin-left: 0;"> <div class="layui-input-block" style="margin-left: 0;">
@ -270,7 +270,7 @@
</div> </div>
</form> </form>
</div> --> </div> -->
<div class="layui-tab-item" id="wechat"> <div class="layui-tab-item layui-show" id="wechat">
<div class="wechat-login"> <div class="wechat-login">
<div class="container"> <div class="container">
<h2>微信扫码登录</h2> <h2>微信扫码登录</h2>
@ -287,130 +287,138 @@
</div> </div>
</div> </div>
<script> <script>
layui.use(['form', 'element', 'jquery'], function () { // 全局变量
var form = layui.form; var checkLoginTimer = null;
var element = layui.element; var currentSceneStr = '';
var $ = layui.jquery; var currentTicket = '';
var layer = layui.layer; var qrcodeExpireTime = 0;
var $ = layui.jquery;
// 微信登录相关变量 // 获取微信登录二维码
var checkLoginTimer = null; function getQrcode() {
var currentSceneStr = ''; $.ajax({
var currentTicket = ''; url: '/index/wechat/getLoginTicket',
var qrcodeExpireTime = 0; // 二维码过期时间 type: 'GET',
success: function(res) {
// 获取微信登录二维码 if (res.code === 0) {
function getQrcode() { $('#qrcode').attr('src', res.data.url);
$.ajax({ currentSceneStr = res.data.scene_str;
url: '/index/wechat/getLoginTicket', currentTicket = res.data.ticket;
type: 'GET', // 设置二维码过期时间5分钟
success: function(res) { qrcodeExpireTime = new Date().getTime() + (res.data.expire_seconds * 1000);
if (res.code === 0) { $('#status').text('等待扫码...');
$('#qrcode').attr('src', res.data.url); $('#error').text('');
currentSceneStr = res.data.scene_str; // 开始检查登录状态
currentTicket = res.data.ticket; startCheckLogin();
// 设置二维码过期时间5分钟 } else {
qrcodeExpireTime = new Date().getTime() + (res.data.expire_seconds * 1000); $('#error').text('获取二维码失败:' + res.msg);
$('#status').text('等待扫码...');
$('#error').text('');
// 开始检查登录状态
startCheckLogin();
} else {
$('#error').text('获取二维码失败:' + res.msg);
}
},
error: function() {
$('#error').text('获取二维码失败,请刷新页面重试');
} }
}); },
} error: function() {
$('#error').text('获取二维码失败,请刷新页面重试');
}
});
}
// 重新生成二维码 // 开始检查登录状态
function reGenerateQrcode() { function startCheckLogin() {
if (!currentSceneStr) { if (checkLoginTimer) {
getQrcode(); clearInterval(checkLoginTimer);
}
checkLoginTimer = setInterval(function() {
// 检查二维码是否过期
if (new Date().getTime() > qrcodeExpireTime) {
clearInterval(checkLoginTimer);
$('#status').text('二维码已过期,请点击刷新');
$('#qrcode').css('opacity', '0.5');
return; return;
} }
// 清除之前的定时器
if (checkLoginTimer) {
clearInterval(checkLoginTimer);
checkLoginTimer = null;
}
$.ajax({ $.ajax({
url: '/index/wechat/reGenerateQrcode', url: '/index/wechat/checkLoginStatus',
type: 'POST', type: 'POST',
data: { data: {
scene_str: currentSceneStr scene_str: currentSceneStr,
ticket: currentTicket
}, },
success: function(res) { success: function(res) {
if (res.code === 0) { if (res.code === 1) {
$('#qrcode').attr('src', res.data.url); // 登录成功
currentSceneStr = res.data.scene_str; clearInterval(checkLoginTimer);
currentTicket = res.data.ticket; $('#status').text('登录成功,正在跳转...');
// 设置新的二维码过期时间5分钟 // 保存用户信息到localStorage
qrcodeExpireTime = new Date().getTime() + (res.data.expire_seconds * 1000); if (res.data) {
$('#status').text('等待扫码...'); localStorage.setItem('user_account', res.data.user_account);
$('#error').text(''); localStorage.setItem('expire_time', res.data.expire_time);
// 开始检查登录状态 localStorage.setItem('is_auto_login', res.data.is_auto_login);
startCheckLogin(); }
} else { // 设置cookie
$('#error').text('刷新二维码失败:' + res.msg); document.cookie = `user_account=${res.data.user_account}; path=/; max-age=${7*24*3600}`;
document.cookie = `user_avatar=${res.data.avatar}; path=/; max-age=${7*24*3600}`;
document.cookie = `user_name=${res.data.name}; path=/; max-age=${7*24*3600}`;
document.cookie = `open_id=${res.data.openid}; path=/; max-age=${7*24*3600}`;
// 跳转到首页或其他页面
setTimeout(function() {
window.location.href = '/';
}, 1000);
} else if (res.code === 0) {
// 更新状态信息
$('#status').text(res.msg);
} }
}, },
error: function() { error: function() {
$('#error').text('刷新二维码失败,请重试'); $('#error').text('检查登录状态失败,请重试');
} }
}); });
}, 2000); // 每2秒检查一次
}
// 重新生成二维码的全局函数
function reGenerateQrcode() {
if (!currentSceneStr) {
getQrcode();
return;
} }
// 开始检查登录状态 // 清除之前的定时器
function startCheckLogin() { if (checkLoginTimer) {
if (checkLoginTimer) { clearInterval(checkLoginTimer);
clearInterval(checkLoginTimer); checkLoginTimer = null;
} }
checkLoginTimer = setInterval(function() { $.ajax({
// 检查二维码是否过期 url: '/index/wechat/reGenerateQrcode',
if (new Date().getTime() > qrcodeExpireTime) { type: 'POST',
clearInterval(checkLoginTimer); data: {
$('#status').text('二维码已过期,请点击刷新'); scene_str: currentSceneStr
$('#qrcode').css('opacity', '0.5'); },
return; success: function(res) {
if (res.code === 0) {
$('#qrcode').attr('src', res.data.url);
currentSceneStr = res.data.scene_str;
currentTicket = res.data.ticket;
// 设置新的二维码过期时间5分钟
qrcodeExpireTime = new Date().getTime() + (res.data.expire_seconds * 1000);
$('#status').text('等待扫码...');
$('#error').text('');
// 开始检查登录状态
startCheckLogin();
} else {
$('#error').text('刷新二维码失败:' + res.msg);
} }
},
error: function() {
$('#error').text('刷新二维码失败,请重试');
}
});
}
$.ajax({ layui.use(['form', 'element', 'jquery'], function () {
url: '/index/wechat/checkLoginStatus', var form = layui.form;
type: 'POST', var element = layui.element;
data: { var layer = layui.layer;
scene_str: currentSceneStr,
ticket: currentTicket
},
success: function(res) {
if (res.code === 1) {
// 登录成功
clearInterval(checkLoginTimer);
$('#status').text('登录成功,正在跳转...');
// 保存用户信息到localStorage
if (res.data && res.data.user_info) {
localStorage.setItem('user_info', JSON.stringify(res.data.user_info));
}
// 跳转到首页或其他页面
setTimeout(function() {
window.location.href = '/';
}, 1000);
} else if (res.code === 0) {
// 更新状态信息
$('#status').text(res.msg);
}
},
error: function() {
$('#error').text('检查登录状态失败,请重试');
}
});
}, 2000); // 每2秒检查一次
}
// 页面加载完成后获取二维码 // 页面加载完成后获取二维码
$(document).ready(function() { $(document).ready(function() {