需求 :小程序使用微信登錄,後端獲取用戶詳細(包含openid,unionid)寫入數據庫,並生成token
小程序登錄獲取token
1.通過wx.login獲取到code,
2.wx.getUserInfo 獲取到加密數據encryptedData ,及iv ,
3.將數據發送到後臺換取token
小程序代碼
var that = this;
wx.getSetting({
success(res) {
var status = res.authSetting['scope.userInfo']
if (status) {
wx.login({
success(res) {
if (res.code) {
var code = res.code;
wx.getUserInfo({
success(res) {
wx.showLoading({
title: '登陸中',
mask: true
});
that.login(code, res.encryptedData, res.iv)
}
})
}
}
})
}
}
})
/**
* 登錄獲取token
*/
function login(code, encrypteData, iv) {
var that = this
wx.showToast({
title: '正在登錄...',
icon: 'loading',
duration: 5000
});
wx.request({
url: url,
method: 'get',
data: {
code: code,
encrypteData: encrypteData,
iv: iv
},
header: {
'Content-Type': 'application/json'
},
success: function(res) {
if (res.data.code == 0) {
that.globalData.token = res.data.data
wx.hideLoading()
} else
console.error(res);
},
fail: function() {
wx.showToast({
title: '網絡錯誤!',
duration: 2000
})
},
complete: function() {
}
})
服務端註冊
1.用前端提交的token請求微信服務器獲取session_key,
2.用session_key,iv將加密數據進行解密得到用戶信息
3.判斷是否註冊過,寫入數據庫
4.生成token
代碼
/**
* Notes:登錄並註冊
* @auther: xxf
* Date: 2019/9/29
* Time: 14:22
* @param Request $request
* @return \think\response\Json
*/
public function login(Request $request)
{
$code = $request->post('code');
$encryptedData = $this->request->post('encryptedData');
$iv = $this->request->post('iv');
$model = new User();
$res = $model->userLogin($code,$iv,$encryptedData);
return json($res);
}
public function userLogin($code,$iv,$encrypteData)
{
try {
$url = "https://api.weixin.qq.com/sns/jscode2session?appid=$this->appId&secret=$this->appSecret&js_code=$code&grant_type=authorization_code";
$tokenValue = $this->httpGet($url);
$data = $this->decryptData($this->appId,$tokenValue->session_key,$encrypteData,$iv);
$user = User::where('openid',$tokenValue->openid)->find();
if($user instanceof User) {
$user->lasttime = time();
$user->head = $data['avatarUrl'];
$user->save();
$mid = $user->id;
}else{
$userData = array([
'openid' => $data['openId'],
'name' => $data['nickName'],
'head' => $data['avatarUrl'],
'sex' => $data['gender'],
'address' => $data['country'].$data['province'].$data['city'],
'addtime' => time(),
'lasttime' => time(),
]);
$mid = $this->insertGetId($userData);
}
if ($mid)
{
$jwtToken = new Token();
$tokenData = array(
'mid' => $mid,
);
$token = $jwtToken->createToken($tokenData, 86400)['token'];
return ['data' => $token, 'code' => 0, 'msg' => 'success'];
} else
return ['data' => '', 'code' => 1, 'msg' => '異常'];
} catch (\Exception $e)
{
return ['data' => '', 'code' => 1, 'msg' => $e->getMessage()];
}
}
/**
* Notes:數據解密
* @auther: xxf
* Date: 2019/9/29
* Time: 15:44
* @param $appId
* @param $session_key
* @param $encryptedData
* @param $iv
* @return mixed|string
* @throws \Exception
*/
private function decryptData( $appId,$session_key,$encryptedData, $iv)
{
if (strlen($session_key) != 24 || strlen($iv) != 24) {
throw new \Exception("encodingAesKey或iv 非法");
}
$aesKey=base64_decode($session_key);
$aesIV=base64_decode($iv);
$aesCipher=base64_decode($encryptedData);
$result=openssl_decrypt( $aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);
$dataObj=json_decode( $result );
$result = json_decode($result,true);
if( $dataObj == NULL )
throw new \Exception("解密失敗");
if( $dataObj->watermark->appid != $appId )
throw new \Exception("解密失敗");
return $result;
}
private function httpGet($url) {
$curl = curl_init();
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_TIMEOUT, 500);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_URL, $url);
$res = curl_exec($curl);
curl_close($curl);
return json_decode($res);
}
其他業務鑑權驗證token
小程序後續請求時,在header裏攜帶token
wx.request({
url: _api,
header: {
'content-type': 'application/json',
'Authorization': token
},
method: 'POST',
data: data,
success: function (res) {
if(res.statusCode == 401)
{
wx.showToast({
title: '未登錄',
image: "/assets/icon/icon-warning.png",
});
}
success(res);
}
});
後臺中間件代碼
public function handle($request, \Closure $next)
{
$token = $request->header('AUTHORIZATION');
$jwtToken = new Token();
$checkToken = $jwtToken->checkToken($token);
$data = (array)$checkToken['data']['data'];
$mid = $data['mid'] ?? 0 ;
$user = User::where('id',$mid)->find();
if($user instanceof User){
$request->user = $user;
return $next($request);
}else{
$res = [
'data' => '',
'code'=>1,
'msg'=>'未登錄'
];
sendResponse($res, 401, 'Unauthorized');
}
}
有關token生成請參看我的其他博客