網上找了很多教程都不好使,最后自己又研究了一番,終于成功了
一、總體設計
小程式登錄流程:客戶端通過呼叫wx.login(),獲取登錄憑證(code),將此code發往服務器,服務器通過呼叫 auth.code2Session 介面,使用 code 換取 openid、unionid、session_key 等資訊,
參考官方給出的時序圖:

本實體中將openid作為用戶唯一標識,存入資料庫中,服務器后端通過ThinkPHP框架實作兩個介面:
http://localhost/srclib/index.php/Home/User/wxlogin // 登錄介面
http://localhost/srclib/index.php/Home/User/wxsign // 首次登錄(微信授權登錄)介面
1. 登錄狀態的維持
小程式在初始化時,在小程式onLaunch生命周期函式中呼叫wx.login(),向登錄介面發送請求,將code發送給服務器,服務器接收到code后,呼叫https://api.weixin.qq.com/sns/jscode2session介面,將code,appid和appSecret發送給微信官方服務器,服務器會收到用戶唯一標識openid和會話密鑰 session_key等資訊,
此時服務器后臺在資料庫User表中查詢openid:
-
如果在User表中沒有查到該記錄,則說明此用戶是新用戶,還未授權微信登錄,服務器回傳客戶端的狀態碼err_code值為1,表示不存在該用戶,需要用戶手動授權微信登錄;
-
如果在User表中查到了該記錄,則表示用戶已授權微信登錄,此時服務器回傳客戶端的狀態碼err_code值為0,表示登錄成功,服務器將用戶資訊和狀態碼發送至前端,
客戶端在接收到狀態碼后判斷:
-
若狀態碼為0,則表示登錄成功,客戶端接收到用戶資訊后,通過呼叫wx.setStorageSync()將用戶資訊加入本地快取,并將登錄狀態設定為true,此時實作了登錄狀態的維持;
-
若狀態碼為1,表示用戶還未授權登錄,此時跳轉至auth頁等待用戶的授權操作,
首次授權后,小程式每次啟動時,自動呼叫登錄介面,并將在本地快取中更新用戶資訊和登錄狀態,小程式其他頁面在初始化時呼叫_initial()函式,從本地快取中取出用戶資訊和登錄狀態,賦值給全域變數userInfo和loginState,此后小程式頁面渲染時便可從全域變數獲取用戶資訊,設定給頁面物件的data屬性值,
2. 微信授權登錄的實作
微信官方提供了wx.getUserProfile介面,使用獲取用戶資訊,在頁面中加入一個button,監聽用戶點擊,點擊后獲取用戶資訊,本實體中主要獲取了用戶昵稱nickName和用戶頭像地址avatarUrl,之后向(微信授權登錄)首次登錄介面發送請求,輸入資料為code、nickName和avatarUrl,
服務端接收到這些引數后,首先呼叫https://api.weixin.qq.com/sns/jscode2session介面,將code,appid和appSecret發送給微信官方服務器,服務器會收到用戶唯一標識openid等引數,然后在資料庫User表中查詢該openid:
-
如果在User表中沒有查到該記錄,則將openid、nickName和avatarUrl構建為一條用戶記錄資料,插入User表中,服務器回傳客戶端的狀態碼err_code值為0,表示新用戶授權登錄成功,服務器將用戶資訊和狀態碼發送至前端;
-
如果在User表中查到了該記錄,則表示該用戶重復授權,拋出例外,此時服務器回傳客戶端的狀態碼err_code值為1,
二、步驟說明
1. 用戶首次進入,顯示授權登錄按鈕

2. 點擊授權登錄按鈕,出現提示彈窗

3. 點擊允許后,登錄成功,跳轉至個人中心頁

4. 此后用戶再次進入小程式,已自動登錄,實作了登錄狀態的維持

三、完整代碼
1. 小程式前端
app.js
// app.js
App({
globalData: {
loginState: false, // 用戶登錄狀態
userInfo: null // 用戶資訊
},
onLaunch() {
this.login() // 登錄
},
_initial() { // Page初始化函式,用于讀取本地快取,并更新全域變數
this.globalData.userInfo = wx.getStorageSync('userInfo')
this.globalData.loginState = wx.getStorageSync('loginState')
console.log("登錄狀態:"+this.globalData.loginState)
console.log("用戶資訊:")
console.log(this.globalData.userInfo)
},
login() {
let _this = this
// 登錄請求
wx.login({
success: res => {
wx.request({
url: 'http://localhost/srclib/index.php/Home/User/wxlogin',
method: 'post',
data: {
code: res.code
},
header: {
"Content-Type": "application/x-www-form-urlencoded"
},
success: function (res) {
if(res.data.error_code == 1) { // 用戶未授權登錄
console.log("error")
wx.setStorageSync('loginState', false)
wx.navigateTo({ // 跳轉至授權頁,等待用戶授權
url: '../auth/auth',
})
} else if(res.data.error_code == 0) { // 登錄成功
wx.setStorageSync('userInfo', res.data.data) // 更新本地快取
wx.setStorageSync('loginState', true)
}
}
})
}
})
}
})
profile.js
// pages/profile/profile.js
const app = getApp()
const globalData = getApp().globalData
Page({
data: {
userInfo: null
},
onLoad() {
app._initial() // 頁面初始化
this.setData({
userInfo: globalData.userInfo
})
}
})
auth.js
// auth.js
const app = getApp()
const globalData = getApp().globalData
Page({
data: {
userInfo: null
},
onLoad() {
app._initial() // 頁面初始化
},
getUserProfile(e) {
// 使用wx.getUserProfile獲取用戶資訊
wx.getUserProfile({
desc: '展示用戶資訊', // 宣告獲取用戶個人資訊后的用途,后續會展示在彈窗中
success: (res) => {
globalData.userInfo = res.userInfo
this.setData({
userInfo: globalData.userInfo
})
this.sign()
}
})
},
sign() {
let _this = this
wx.showLoading({
title: '加載中',
})
// 用戶首次登錄請求
wx.login({
success: res => {
wx.request({
url: 'http://localhost/srclib/index.php/Home/User/wxsign',
method: 'post',
data: {
code: res.code,
name: globalData.userInfo.nickName,
avatarUrl: globalData.userInfo.avatarUrl
},
header: {
"Content-Type": "application/x-www-form-urlencoded"
},
success: function (res) {
if(res.data.error_code == 1) { // 用戶登錄失敗
console.log("error")
} else if(res.data.error_code == 0) { // 用戶登錄成功
wx.setStorageSync('userInfo', res.data.data) // 更新本地快取
wx.setStorageSync('loginState', true)
wx.hideLoading()
wx.showToast({
title: '授權成功',
icon: 'success',
duration: 2000,
complete: (res) => {
wx.navigateTo({ // 跳轉至個人中心頁
url: '../profile/profile',
})
},
})
}
}
})
}
})
}
})
profile.wxml
<!--pages/profile/profile.wxml-->
<view class="container">
<view class="userinfo">
<image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.face_url}}" mode="cover"></image>
<text class="userinfo-nickname">{{userInfo.username}}</text>
</view>
</view>
auth.wxml
<!--auth.wxml-->
<view class="container">
<button type="primary" bindtap="getUserProfile">授權微信登錄</button>
</view>
2. 服務器后端
<?php
namespace Home\Controller;
use Think\Controller;
class UserController extends BaseController
{
/**
* 微信登錄
* @return [type] [description]
*/
public function wxlogin()
{
// 校驗引數是否存在
if (!$_POST['code']) {
$return_data = array();
$return_data['error_code'] = 2;
$return_data['msg'] = '引數不足: code';
$this->ajaxReturn($return_data);
} else {
$appid = "wxc6a376950e1c45c0"; // appid
$secret = "632hjdcba4c2b972c591738hdga91fvg"; // app密鑰
$code = $_POST['code']; // 小程式傳來的code值
$curl = curl_init();
$url = "https://api.weixin.qq.com/sns/jscode2session?appid=" . $appid . "&secret=" . $secret . "&js_code=" . $code . "&grant_type=authorization_code";
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($curl);
$json = json_decode($result); // 對json資料解碼
$arr = get_object_vars($json);
$openid = $arr['openid'];
curl_close($curl);
// 檢驗是否已經授權登錄
$User = M('User');
// 構造查詢條件
$where = array();
$where['openid'] = $openid;
$user = $User->where($where)->find();
if ($user) {
$return_data = array();
$return_data['error_code'] = 0;
$return_data['msg'] = '登錄成功';
$return_data['data']['userid'] = $user['userid'];
$return_data['data']['username'] = $user['username'];
$return_data['data']['face_url'] = $user['face_url'];
$this->ajaxReturn($return_data);
} else {
$return_data = array();
$return_data['error_code'] = 1;
$return_data['msg'] = '不存在該用戶,請授權登錄';
$this->ajaxReturn($return_data);
}
}
}
/**
*首次授權登錄
* @return [type] [description]
*/
public function wxsign()
{
// 校驗引數是否存在
if (!$_POST['code']) {
$return_data = array();
$return_data['error_code'] = 2;
$return_data['msg'] = '引數不足: code';
$this->ajaxReturn($return_data);
} else if (!$_POST['name']) {
$return_data = array();
$return_data['error_code'] = 2;
$return_data['msg'] = '引數不足: name';
$this->ajaxReturn($return_data);
} else if (!$_POST['avatarUrl']) {
$return_data = array();
$return_data['error_code'] = 2;
$return_data['msg'] = '引數不足: avatarUrl';
$this->ajaxReturn($return_data);
} else {
$appid = "wxc6a376950e1c45c0"; // appid
$secret = "632hjdcba4c2b972c591738hdga91fvg"; // app密鑰
$code = $_POST['code']; // 小程式傳來的code值
$curl = curl_init();
$url = "https://api.weixin.qq.com/sns/jscode2session?appid=" . $appid . "&secret=" . $secret . "&js_code=" . $code . "&grant_type=authorization_code";
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($curl);
$json = json_decode($result); // 對json資料解碼
$arr = get_object_vars($json);
$openid = $arr['openid'];
curl_close($curl);
// 檢驗是否已經授權過
$User = M('User');
// 構造查詢條件
$where = array();
$where['openid'] = $openid;
$user = $User->where($where)->find();
if ($user) {
$return_data = array();
$return_data['error_code'] = 1;
$return_data['msg'] = '登錄失敗';
$this->ajaxReturn($return_data);
} else {
// 構建插入的資料
$data = array();
$data['openid'] = $openid;
$data['username'] = $_POST['name'];
$data['face_url'] = $_POST['avatarUrl'];
// 插入資料
$result = $User->add($data);
// add資料添加成功之后,回傳的就是該條資料的id
if ($result) {
// 插入資料執行成功
$return_data = array();
$return_data['error_code'] = 0;
$return_data['msg'] = '登錄成功';
$return_data['data']['userid'] = $result;
$return_data['data']['username'] = $_POST['name'];
$return_data['data']['face_url'] = $_POST['avatarUrl'];
$this->ajaxReturn($return_data);
} else {
// 插入資料執行失敗
$return_data = array();
$return_data['error_code'] = 1;
$return_data['msg'] = '登錄失敗';
$this->ajaxReturn($return_data);
}
}
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/273654.html
標籤:其他
下一篇:一文帶你走進介面測驗
