前提:把前端域名和后端接口域名添加到微信公众号网页授权
我在wiondows系统服务器测试的。所以启动服务是点击运行文件 (vendor/GatewayWorker/start_for_win.bat )
1. 前端(原生)
pc页面二维码页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>微信扫码登陆</title>
<style>
*{
margin: 0;
padding: 0;
}
.posthqrcode{
width: 100vw;
height: calc(100vh - 40px);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
}
</style>
</head>
<body>
<div class="posthqrcode">
<div id="qrcode"></div>
<p>请使用微信扫码登陆</p>
</div>
<script src="./js/ajax.js"></script>
<script src="./js/jquery.min.js"></script>
<script src="./js/jquery.qrcode.min.js"></script>
<script>
// 扫码登陆
let uuid = '';
let p = document.querySelector('p');
ajax({
url:"http://liao.xddtuoguan.com/api/wechatParam",
type:"GET",
is_formdata:false
},false).then(res=>{
if(res.code == 200){
let href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+res.data.appid+"&redirect_uri="+encodeURI('网址/home/wxwechat.html?uuid='+res.data.uuid)+"&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect"
$("#qrcode").qrcode({width:200, height:200,text:href});
// WebSocket 监听 扫码登陆
let ws = new WebSocket("ws://网址:8282");
ws.onopen = function(){
// console.log("连接成功");
};
ws.onmessage = function(e){
let data = JSON.parse(e.data);
if(data.type === 'bind'){
ajax({
url:"网址/api/bind",
type:"POST",
is_formdata:false,
data:{
uuid:res.data.uuid,
client_id:data.client_id
}
},false).then(res=>{
if(res.code == 200){
console.log("绑定成功");
}
});
}else if(data.type === 'scanned'){
p.innerText = data.msg;
}
else if(data.type === 'OnLogin'){
localStorage.setItem('home_token',data.token);
window.location.href = "首页";
}
};
}
});
</script>
</body>
</html>
手机扫码页面
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>微信一键登录</title>
<style>
*{
margin: 0;
padding: 0;
}
body{
background-color: #f5f5f5;
}
#empower{
width: 80%;
background-color: white;
margin: 0 auto;
margin-top: 20%;
text-align: center;
border-radius: 10px;
padding: 20px;
}
.title{
width: 80%;
background-color: white;
margin: 0 auto;
margin-top: 20%;
text-align: center;
border-radius: 10px;
padding: 20px;
font-size: 20px;
display: none;
}
.title img{
width:90%;
margin-bottom: 20px;
}
#empower p{
font-size: 20px;
margin-bottom: 20px;
}
#empowerBtn{
width: 100%;
height: 40px;
background-color: #1AAD19;
border-radius: 5px;
color: white;
font-size: 18px;
border: none;
}
</style>
</head>
<body>
<div class="title">
<p></p>
</div>
<div id="empower">
<p>是否确认登陆</p>
<button id="empowerBtn">确认</button>
</div>
<script src="./js/ajax.js"></script>
<script>
//接受code
var code = getUrlParam('code');
var uuid = getUrlParam('uuid');
var empower = document.getElementById('empower');
var btn = document.getElementById('empowerBtn');
var title = document.getElementsByClassName('title')[0];
var titleP = title.getElementsByTagName('p')[0];
// 确认授权
btn.onclick = function(){
ajax({
url:"http://网址/api/wxwechat",
type:"post",
data:{code:code,uuid:uuid},
is_formdata:false
},false).then(res=>{
empower.style.display = 'none';
titleP.innerText = res.msg;
title.style.display = 'block';
var img = document.createElement('img');
if(res.code === 200){
img.src = './images/wxsueecc.jpg';
titleP.style.color = 'green';
}else{
img.src = './images/wxerror.jpg';
titleP.style.color = 'red';
}
title.insertBefore(img,title.firstElementChild);
});
}
// 修改扫码状态
ajax({
url:"http://网址/api/set_status",
type:"post",
data:{uuid:uuid},
is_formdata:false
},false).then(res=>{
if(res.code !== 200){
empower.style.display = 'none';
titleP.innerText = res.msg;
title.style.display = 'block';
var img = document.createElement('img');
img.src = './images/wxerror.jpg';
titleP.style.color = 'red';
title.insertBefore(img,title.firstElementChild);
}
});
</script>
</body>
</html>
2. 后端thinkphp
<?php
namespace app\api\controller;
use think\cache\driver\Redis;
use app\model\Users;
use app\auth\Jwtauth;
use GatewayClient\Gateway;
class WxLogin extends common
{
/**
* @return void
*/
public function initialize()
{
parent::initialize();
$this->appid = config('weixin.appid');
$this->appsecret = config('weixin.appsecret');
//redis
$this->_redis = new Redis();
Gateway::$registerAddress = '127.0.0.1:1238';
}
/**
* gatewayworker 通知
*/
public function sendToUid($uuid,$type,$msg,$token=''){
$data = [
'type'=>$type,
'msg'=>$msg,
'token'=>$token
];
Gateway::sendToUid($uuid,json_encode($data));
}
/**
* 微信扫码
* 获取appid appsecret
*/
public function wechatParam(){
// 生成uuid
$uuid = $this->uuid_create();
// 存入redis
$this->_redis->set('uuid_'.$uuid,time(),300);
// 返回
return return_json(200,'获取成功',['appid'=>$this->appid,'uuid'=>$uuid]);
}
/**
* 修改状态扫码中
*
*/
public function set_status(){
$uuid = Request()->param('uuid');
if(!$uuid){
//通知
$this->sendToUid($uuid,'scanned','参数错误,请刷新二维码');
return return_json(201,'参数错误,请刷新二维码');
}
// 判断redis uuid是否存在
if(!$this->_redis->has('uuid_'.$uuid)){
//通知
$this->sendToUid($uuid,'scanned','二维码失效,请刷新二维码');
return return_json(201,'二维码失效,请重新扫码!');
}
//通知
$this->sendToUid($uuid,'scanned','已扫码成功,未确定登陆');
return return_json(201);
}
/**
* @return void
*
*/
public function wxwechat(){
//获取code
$code = getinput('code');
$uuid = getinput('uuid');
// 判断redis uuid是否存在
if(!$this->_redis->has('uuid_'.$uuid)){
return return_json(201,'二维码失效,请重新扫码!');
}
//获取access_token openid
$return_data = json_decode($this->curl_get_contents("https://api.weixin.qq.com/sns/oauth2/access_token?appid=".$this->appid."&secret=".$this->appsecret."&code=".$code."&grant_type=authorization_code"),true);
$access_token = $return_data['access_token'];
$openid = $return_data['openid'];
//查询是否已绑定
$users_id = Users::where('openid',$openid)->value('users_id');
if($users_id){
// jwt
$token = Jwtauth::getToken($users_id);
}else{
//获取信息
$user_info = json_decode($this->curl_get_contents("https://api.weixin.qq.com/sns/userinfo?access_token=".$access_token."&openid=".$openid."&lang=zh_CN"),true);
$insert_data = [
'openid'=>$user_info['openid'],
'users_name'=>$user_info['nickname'],
'img_url'=>$user_info['headimgurl']
];
//新增
$insert_status = Users::create($insert_data);
if (!$insert_status){
return return_json(201,'登陆失败,请重新扫码');
}
// jwt
$token = Jwtauth::getToken($insert_status->id);
}
$this->sendToUid($uuid,'OnLogin','登录成功',$token);
return return_json(200,'登录成功');
}
//绑定user_id
public function bind(){
$uuid = request()->param('uuid');
$client_id = request()->param('client_id');
Gateway::bindUid($client_id,$uuid);
return return_json(200,'绑定成功');
}
//生成uuid
public function uuid_create(){
$charid = strtoupper(md5(uniqid(mt_rand(), true)));
$uuid = substr($charid, 0, 8)
.substr($charid, 8, 4)
.substr($charid,12, 4)
.substr($charid,16, 4)
.substr($charid,20,12);
return $uuid;
}
/**
* 远程获取
*/
public function curl_get_contents($url) {
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
}
3. gatewayworker 修改
vendor/GatewayWorker/applocations/start_gateway.php
// gateway 进程,这里使用Text协议,可以用telnet测试
$gateway = new Gateway("Websocket://网址:8282");
// gateway名称,status方便查看
$gateway->name = 'WuMingHaoGateway';
4.启动服务
vendor/GatewayWorker/start_for_win.bat 双击运行