微信小程序登录
好久没写东西了,写点东西 滥竽充数 记录一下。
大体登录流程:前端调用wx.login()接口就可获取登录凭证(js_code)传给后端,后端再使用小程序的appid、secret和这个js_code获取到用户的openID和session_key,数据库如果有这个openID的话直接就登录成功。
注册流程:前端把encryptedData、iv以及用户头像、昵称传过来,后端解密一下encryptedData获得手机号,至此就获取到了用户必要的注册信息了,然后再把上面登录步骤获取的openid一起插入数据库,即注册成功。
简单直接上代码,thinkphp的代码
代码
/**
* 微信小程序登录
*
* @return response|\think\response\Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function wx_login()
{
//组装数据
$data = [
'appid' => Config::get('appid'),//配置文件获取appid
'secret' => Config::get('secret'),//配置文件获取secret
'js_code' => Request::post('code'),//post请求接收code参数
'grant_type' => 'authorization_code',
];
if (empty($data['appid']) || empty($data['secret'] || empty($data['js_code']))) return Json::error('缺少必要参数');
//组装get请求
$url = 'https://api.weixin.qq.com/sns/jscode2session?' . http_build_query($data);
$response = json_decode($this->curl($url), true); //发起请求
if (empty($response['openid'])) return Json::unLogin('系统异常');
$user = Db::name('user')->where('openid', $response['openid'])->findOrEmpty();//查找用户
if (!empty($user)) return Json::success('登录成功', ['token' => JWT::encode(['id' => $user['id'], 'password' => ''], $this->key)]);
//我这里是直接把session_key和openid用JWT压到token里面,能防止注册接口被随便插openID注册,因为注册必须要有我的这个token才行
return Json::error('用户未注册', [
'token' => JWT::encode([
'session_key' => $response['session_key'],
'openid' => $response['openid'],
], $this->key),
]);
}
private function curl(string $url): string
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // https请求 不验证证书和hosts
$result = curl_exec($curl);
curl_close($curl);
return $result;
}
/**
* 微信小程序用户注册
*
* @return response|\think\response\Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function wx_register()
{
//接收参数
$request = Request::only(['token', 'encryptedData', 'iv', 'nick_name', 'avatar']);
$validate = Validate::make([
'token' => 'require',
'encryptedData' => 'require',
'iv' => 'require',
'nick_name' => 'require',
'avatar' => 'require',
]);
if (!$validate->check($request)) return Json::error($validate->getError());//这里做数据验证
try {
//这里做token解析
$data = (array)JWT::decode($request['token'], $this->key, ['HS256']);
} catch (Exception $e) {
return Json::error('Token有误');
}
if (!isset($data['openid']) || !isset($data['session_key'])) return Json::error('Token有误');
//解密encryptedData获取手机号
$info = $this->decryptData($request['encryptedData'], $request['iv'], Config::get('appid'), $data['session_key']);
$user = [];
$user['openid'] = $data['openid'];
$user['nick_name'] = $request['nick_name'];
$user['avatar'] = $request['avatar'];
$user['ctime'] = time();
$user['phone'] = $info['data']['phoneNumber'];
$uid = Db::name('user')->insertGetId($user);
if ($uid) return Json::success('注册成功', ['token' => JWT::encode(['id' => $uid, 'password' => ''], $this->key)]);
return Json::error('注册失败');
}
/**
* 检验数据的真实性,并且获取解密后的明文.
*
* @param string $encryptedData
* @param string $iv
* @param string $appid
* @param string $sessionKey
*
* @return array
*/
private function decryptData(string $encryptedData, string $iv, string $appid, string $sessionKey): array
{
if (mb_strlen($sessionKey) != 24) return ['status' => false, 'msg' => 'encodingAesKey 非法'];
$aesKey = base64_decode($sessionKey);
if (mb_strlen($iv) != 24) return ['status' => false, 'msg' => 'iv 非法'];
$aesIV = base64_decode($iv);
$aesCipher = base64_decode($encryptedData);
$result = openssl_decrypt($aesCipher, 'AES-128-CBC', $aesKey, 1, $aesIV);
$data = json_decode($result, true);
if (empty($data)) return ['status' => false, 'msg' => 'aes 解密失败'];
if (!isset($data['watermark']) || !isset($data['watermark']['appid']) || $data['watermark']['appid'] != $appid) {
return ['status' => false, 'msg' => 'aes 解密失败'];
}
return ['status' => false, 'data' => $data];
}
大体就这样