本文目录导读:

我来详细介绍ThinkPHP项目中实现微信登录与授权的完整方案。
基础准备
环境配置
// config/wechat.php 配置文件
return [
'app_id' => 'your_app_id',
'app_secret' => 'your_app_secret',
'redirect_uri' => 'https://yourdomain.com/wechat/callback',
'scope' => 'snsapi_userinfo', // snsapi_base 或 snsapi_userinfo
'oauth_url' => 'https://open.weixin.qq.com/connect/oauth2/authorize',
'token_url' => 'https://api.weixin.qq.com/sns/oauth2/access_token',
'userinfo_url' => 'https://api.weixin.qq.com/sns/userinfo'
];
安装依赖
composer require overtrue/wechat
网页授权登录
发起授权请求
<?php
namespace app\wechat\controller;
use think\Controller;
use think\facade\Config;
use think\facade\Session;
class Login extends Controller
{
protected $wechatConfig;
public function __construct()
{
$this->wechatConfig = Config::get('wechat.');
}
// 发起微信授权
public function authorize()
{
// 生成随机state参数防止CSRF
$state = md5(uniqid(rand(), true));
Session::set('wechat_state', $state);
$param = [
'appid' => $this->wechatConfig['app_id'],
'redirect_uri' => $this->wechatConfig['redirect_uri'],
'response_type' => 'code',
'scope' => $this->wechatConfig['scope'],
'state' => $state
];
$url = $this->wechatConfig['oauth_url'] . '?' . http_build_query($param) . '#wechat_redirect';
return redirect($url);
}
}
回调处理
// 回调处理
public function callback()
{
$code = input('get.code');
$state = input('get.state');
// 验证state防止CSRF
if ($state !== Session::get('wechat_state')) {
return json(['code' => -1, 'msg' => '非法请求']);
}
// 获取access_token
$tokenInfo = $this->getAccessToken($code);
if (isset($tokenInfo['errcode'])) {
return json(['code' => -1, 'msg' => $tokenInfo['errmsg']]);
}
// 获取用户信息
$userInfo = $this->getUserInfo($tokenInfo);
// 处理用户登录
$result = $this->processLogin($tokenInfo, $userInfo);
return $result;
}
// 获取access_token
private function getAccessToken($code)
{
$url = $this->wechatConfig['token_url'];
$params = [
'appid' => $this->wechatConfig['app_id'],
'secret' => $this->wechatConfig['app_secret'],
'code' => $code,
'grant_type' => 'authorization_code'
];
$response = Http::get($url, $params);
return json_decode($response, true);
}
// 获取用户信息
private function getUserInfo($tokenInfo)
{
$url = $this->wechatConfig['userinfo_url'];
$params = [
'access_token' => $tokenInfo['access_token'],
'openid' => $tokenInfo['openid'],
'lang' => 'zh_CN'
];
$response = Http::get($url, $params);
return json_decode($response, true);
}
用户登录处理
业务逻辑处理
// 处理用户登录
private function processLogin($tokenInfo, $userInfo)
{
$openid = $userInfo['openid'];
// 检查用户是否存在
$user = UsersModel::where('openid', $openid)->find();
if (!$user) {
// 新用户注册
$userData = [
'openid' => $openid,
'nickname' => $userInfo['nickname'] ?? '',
'avatar' => $userInfo['headimgurl'] ?? '',
'sex' => $userInfo['sex'] ?? 0,
'province' => $userInfo['province'] ?? '',
'city' => $userInfo['city'] ?? '',
'unionid' => $tokenInfo['unionid'] ?? '',
'create_time' => time()
];
$userId = UsersModel::insertGetId($userData);
$user = UsersModel::find($userId);
} else {
// 更新用户信息
$userData = [
'nickname' => $userInfo['nickname'] ?? $user['nickname'],
'avatar' => $userInfo['headimgurl'] ?? $user['avatar'],
'update_time' => time()
];
UsersModel::where('id', $user['id'])->update($userData);
$user = UsersModel::find($user['id']);
}
// 生成登录凭证
$token = $this->createToken($user['id']);
// 记录登录日志
$this->saveLoginLog($user['id']);
// 返回登录信息
return json([
'code' => 1,
'msg' => '登录成功',
'data' => [
'token' => $token,
'user' => $user
]
]);
}
// 生成登录token
private function createToken($userId)
{
$payload = [
'user_id' => $userId,
'iat' => time(),
'exp' => time() + 7200 // 有效期2小时
];
$token = base64_encode(json_encode($payload));
// 保存到缓存
Cache::set('login_token_' . $token, $userId, 7200);
return $token;
}
移动端H5登录
namespace app\wechat\controller;
use think\Controller;
use Overtrue\WeChat\Factory;
class MobileLogin extends Controller
{
protected $app;
public function __construct()
{
$this->app = Factory::officialAccount([
'app_id' => config('wechat.app_id'),
'secret' => config('wechat.app_secret'),
'response_type' => 'array',
'log' => [
'level' => 'debug',
'file' => runtime_path() . '/wechat.log',
],
]);
}
// 微信授权登录
public function oauthLogin()
{
$oauth = $this->app->oauth;
// 设置回调地址
$callbackUrl = url('wechat/MobileLogin/oauthCallback', [], true, true);
// 跳转到授权页面
return redirect($oauth->redirect($callbackUrl));
}
// 回调函数
public function oauthCallback()
{
$oauth = $this->app->oauth;
// 获取OAuth用户信息
$user = $oauth->user();
// 获取用户基本信息
$userInfo = $user->toArray();
// 处理登录逻辑
return $this->processOauthLogin($userInfo);
}
}
扫码登录(网站应用)
生成二维码
namespace app\wechat\controller;
class QrLogin extends Controller
{
// 获取登录二维码
public function getQrCode()
{
$state = md5(rand());
Session::set('qr_state', $state);
// 生成二维码内容
$qrContent = url('wechat/QrLogin/qrCallback', [
'state' => $state
], true, true);
// 生成二维码
$qrCode = new QrCode($qrContent);
// 返回二维码图片
return $qrCode->setSize(220)->setMargin(10)->writeString();
}
// 轮询检查登录状态
public function checkLogin()
{
$state = input('state');
$key = 'qr_login_' . $state;
if (Cache::has($key)) {
$userInfo = Cache::get($key);
Cache::delete($key);
// 完成登录
return json([
'code' => 1,
'msg' => '登录成功',
'data' => $userInfo
]);
}
return json([
'code' => 0,
'msg' => '等待扫码'
]);
}
}
小程序登录
namespace app\wechat\controller;
use think\Controller;
use think\facade\Cache;
class MiniProgram extends Controller
{
protected $config;
public function __construct()
{
$this->config = [
'app_id' => config('wechat.mini_app_id'),
'app_secret' => config('wechat.mini_app_secret'),
];
}
// 小程序登录
public function login()
{
$code = input('code');
$userInfo = input('userInfo/a', []);
// 获取微信登录凭证
$sessionData = $this->code2Session($code);
if (isset($sessionData['errcode'])) {
return json(['code' => -1, 'msg' => $sessionData['errmsg']]);
}
$openid = $sessionData['openid'];
$unionid = $sessionData['unionid'] ?? '';
// 查询或创建用户
$user = $this->findOrCreateUser($openid, $unionid, $userInfo);
// 生成登录凭证
$token = $this->createLoginToken($user['id']);
return json([
'code' => 1,
'msg' => '登录成功',
'data' => [
'token' => $token,
'user_id' => $user['id']
]
]);
}
// code换session
private function code2Session($code)
{
$url = 'https://api.weixin.qq.com/sns/jscode2session';
$params = [
'appid' => $this->config['app_id'],
'secret' => $this->config['app_secret'],
'js_code' => $code,
'grant_type' => 'authorization_code'
];
$response = Http::get($url, $params);
return json_decode($response, true);
}
}
数据库设计
-- 用户表 CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `openid` varchar(50) NOT NULL COMMENT '微信openid', `unionid` varchar(50) DEFAULT NULL COMMENT '微信unionid', `nickname` varchar(100) DEFAULT NULL COMMENT '昵称', `avatar` varchar(255) DEFAULT NULL COMMENT '头像', `sex` tinyint(4) DEFAULT '0' COMMENT '性别 0未知 1男 2女', `province` varchar(50) DEFAULT NULL COMMENT '省份', `city` varchar(50) DEFAULT NULL COMMENT '城市', `country` varchar(50) DEFAULT NULL COMMENT '国家', `phone` varchar(20) DEFAULT NULL COMMENT '手机号', `status` tinyint(4) DEFAULT '1' COMMENT '状态 1正常 0禁用', `last_login_time` int(11) DEFAULT NULL COMMENT '最后登录时间', `create_time` int(11) DEFAULT NULL COMMENT '创建时间', `update_time` int(11) DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`), UNIQUE KEY `openid` (`openid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 登录日志表 CREATE TABLE `user_login_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL COMMENT '用户ID', `login_type` varchar(20) DEFAULT 'wechat' COMMENT '登录类型', `ip` varchar(50) DEFAULT NULL COMMENT '登录IP', `user_agent` varchar(255) DEFAULT NULL COMMENT '浏览器信息', `create_time` int(11) DEFAULT NULL COMMENT '登录时间', PRIMARY KEY (`id`), KEY `user_id` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
安全措施
// 安全防护示例
class Security implements Middleware
{
public function handle($request, \Closure $next)
{
// 1. 验证请求时间戳
$timestamp = $request->header('timestamp');
if (abs(time() - $timestamp) > 300) {
return json(['code' => -1, 'msg' => '请求已过期']);
}
// 2. 验证签名
$sign = $request->header('sign');
$params = $request->param();
ksort($params);
$signStr = http_build_query($params) . '&key=' . config('wechat.sign_key');
if (md5($signStr) !== $sign) {
return json(['code' => -1, 'msg' => '签名验证失败']);
}
// 3. 防止重放攻击
$nonce = $request->header('nonce');
if (Cache::has($nonce)) {
return json(['code' => -1, 'msg' => '重复请求']);
}
Cache::set($nonce, time(), 300);
return $next($request);
}
}
前端集成
<!-- 前端登录按钮 -->
<script>
// 微信登录
function wechatLogin() {
window.location.href = '/wechat/Login/authorize';
}
// 获取登录状态
function checkLoginStatus() {
$.ajax({
url: '/user/check-login',
method: 'GET',
success: function(response) {
if (response.code === 1) {
// 已登录
showUserInfo(response.data.user);
}
}
});
}
// 保存token到本地
function saveToken(token) {
localStorage.setItem('wechat_token', token);
}
// 请求时携带token
$.ajaxSetup({
beforeSend: function(xhr) {
const token = localStorage.getItem('wechat_token');
if (token) {
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
}
}
});
</script>
注意事项
-
安全方面:
- 使用HTTPS协议
- 验证state参数防止CSRF
- 对敏感信息进行加密存储
- 限制回调地址白名单
-
开发环境:
- 内网穿透工具:ngrok、natapp等
- 配置域名白名单
- 使用测试号进行开发测试
-
生产环境:
- 配置正式AppID和AppSecret
- 服务器IP白名单
- 日志监控和错误告警
这个方案涵盖了微信网页授权、小程序登录、扫码登录等场景,可根据实际需求选择使用。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播