前提
Unionid这个信息,是要把公众号绑定在微信开放平台上之后才有的。没有绑定,即使用户关注了公众号也没用,而小程序端不能直接获取到明文的unionid,只能通过wx.getUserInfo获取到加密数据,所以需要先在小程序端获取到unionid的加密数据后,再传给服务端解密。所以首先需要先去开发平台绑定小程序
登录微信开放平台 — 管理中心 — 小程序 — 绑定小程序
准备工具
小程序端代码:wx.login({
success: res => {
// 发送 res.code 到后台换取 openId, sessionKey, unionId
let obj = {
encryptedData: e.detail.encryptedData,
iv: e.detail.iv,
code: res.code,
rawData: e.detail.rawData,
signature: e.detail.signature
}
wx.request({
url: 'http://xxx/api/wechat/wxlogin',
method: "POST",
header: { "content-type": "application/x-www-form-urlencoded" },
data: obj,
success: r => {
console.log(r)
})
}
})
},
fail: r => {
console.log(r)
}
})
PHP代码:
LoginController:<?php
/**
* @classname LoginController
* @author Bob
* @version $
* @link https://www.bobcoder.cc/
* @Date 2019/5/28
*/
namespace App\Http\Controllers\Api\Comment;
use App\Handlers\WechatConfigHandler;
use App\Http\Controllers\Api\Controller;
use App\Models\User;
use App\Service\WXBizDataCrypt;
use Carbon\Carbon;
use Illuminate\Http\Request;
class LoginController extends Controller
{
protected $wechat;
/**
* LoginController constructor.
* @param WechatConfigHandler $wechat
*/
public function __construct(WechatConfigHandler $wechat)
{
$this->wechat = $wechat;
}
/**
* 微信登录
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
* @link https://www.bobcoder.cc/
* @Date 2019/5/28
* @author Bob
*/
public function wxLogin(Request $request)
{
$code = $request->code;
// 根据 code 获取微信 openid 和 session_key
$miniProgram = $this->wechat->miniProgram();
$data = $miniProgram->auth->session($code);
if (isset($data['errcode'])) {
return response()->json(['code' => -1, 'msg' => 'code已过期或不正确'], 401);
}
// 实例化解密类
$config = $this->wechat->config($request->account);
$pc = new WXBizDataCrypt($config->appid, $data['session_key']);
// 解密
$errCode = $pc->decryptData($request->encryptedData, $request->iv, $data);
//判断解密是否成功
if ($errCode) {
return response()->json([
'code' => 0,
'msg' => $errCode
]);
}
$weappOpenid = $data['openid'];
$unionId = $data['unionId'];
$nickname = $data['nickname'];
$avatar = str_replace('/132', '/0', $data['avatar']);//拿到分辨率高点的头像
$country = $data['country'] ?? '';
$province = $data['province'] ?? '';
$city = $data['city'] ?? '';
$gender = $data['gender'] == '1' ? '1' : '2'; //1为男,2为女
//找到 unionId 对应的用户
$user = User::where('unionId', $unionId)->first();
//没有,就注册一个用户
if (!$user) {
//创建新用户
$user = new User();
$user->open_id = $weappOpenid;
$user->avatarUrl = $avatar;
$user->nickName = $nickname;
$user->country = $country;
$user->province = $province;
$user->city = $city;
$user->gender = $gender;
$user->unionId = $unionId;
$user->save();
//初始化附加值
$user->extra()->firstOrCreate([]);
}
//如果注册过的,就更新下下面的信息
$user->avatarUrl = $avatar;
// 更新用户数据
$user->save();
// 直接创建token并设置有效期
$createToken = $user->createToken($user->open_id);
$createToken->token->expires_at = Carbon::now()->addDays(30);
$createToken->token->save();
$token = $createToken->accessToken;
return response()->json([
'access_token' => $token,
'token_type' => "Bearer",
'expires_in' => Carbon::now()->addDays(30),
'data' => $user,
], 200);
}
}
WXBizDataCrypt:<?php
namespace App\Service;
/**
* 对微信小程序用户加密数据的解密示例代码.
*
* @copyright Copyright (c) 1998-2014 Tencent Inc.
*/
class WXBizDataCrypt
{
private $appid;
private $sessionKey;
/**
* 构造函数
* @param $sessionKey string 用户在小程序登录后获取的会话密钥
* @param $appid string 小程序的appid
*/
public function __construct($appid, $sessionKey)
{
$this->sessionKey = $sessionKey;
$this->appid = $appid;
}
/**
* 检验数据的真实性,并且获取解密后的明文.
* @param $encryptedData string 加密的用户数据
* @param $iv string 与用户数据一同返回的初始向量
* @param $data string 解密后的原文
*
* @return int 成功0,失败返回对应的错误码
*/
public function decryptData($encryptedData, $iv, &$data )
{
if (strlen($this->sessionKey) != 24) {
return 'encodingAesKey 非法';
}
$aesKey=base64_decode($this->sessionKey);
if (strlen($iv) != 24) {
return 'iv 非法';
}
$aesIV=base64_decode($iv);
$aesCipher=base64_decode($encryptedData);
$result=openssl_decrypt( $aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);
$dataObj=json_decode( $result );
if( $dataObj == NULL )
{
return 'aes 解密失败';
}
if( $dataObj->watermark->appid != $this->appid )
{
return 'aes 解密失败';
}
$data = $result;
}
}
解密后的数据{
"openId": "o33VO5bB6B276-qse-aj1CqzXWCg",
"nickName": "Bob",
"gender": 1,
"language": "zh_CN",
"city": "Chengdu",
"province": "Sichuan",
"country": "China",
"avatarUrl":, avatarUrl,
"unionId": unionId,
"watermark": {
"timestamp": 1561702042,
"appid": appid
}
}
转载声明:本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处,尊重他人劳动。
欢迎捐赠赞赏