1. 程式人生 > >微信小程式 + ThinkPHP5 登入態實現

微信小程式 + ThinkPHP5 登入態實現

微信小程式中,一般會涉及三種登入方式:
1. 使用微信賬號登入
2. 自有的賬號註冊和登入
3. 使用其他第三方平臺賬號登入

微信賬號登入流程:
1.  小程式通過wx.login獲取code,發往後臺,後臺以此向微信API換取session_key和openid;

2. 隨機生成字串作為sessionid(key),session_key和openid作為value,存入redis中,為了安全,
    存入的時候還應設定一個超時的時間;

3. 客戶端將返回的sessionid存入storage,呼叫那些需要登入後才有許可權的訪問的後臺服務時,
    你可以將儲存在storage中的sessionid取出並攜帶在請求中,後臺程式碼中獲取到該sessionid後,
    從redis中查詢是否有該sessionid存在,存在的話,即確認該session是有效的,
    繼續後續的程式碼執行,否則進行錯誤處理。

本文采用的是自有的賬號註冊和登入,主要思路和流程如下:

1.  進入小程式首先通過wx.login獲取code,通過後臺介面發往後臺,後臺以此向微信API換取session_key和openid;

2. 判斷資料庫中有無該openid【唯一標識,需和賬號(手機號)繫結】,
    --  如果資料庫中沒有該openid(說明沒有該賬號):
    判斷傳過來的手機號是否為空(登入時會將手機號存到全域性變數),如果不為空,則說明是剛登入過的,然後繫結openid及openid_time(當前時間),
    如果手機號也為空,說明沒登入過,則返回登入失敗資訊,使客戶端跳轉登入頁;
    -- 如果資料庫中有該openid(說明資料庫中有相對應的手機號),
    判斷openid_time距現在的時間是否大於4小時,如果大於,返回登入失敗資訊,使客戶端跳轉登入頁;
    如果小於,則更新openid_time為當前時間,然後返回登入成功資訊及手機號。

3. 登入頁面:判斷資料庫中該手機號是否存在,如果存在,則更新openid_time為當前時間,如果不存在,則新增該手機號使用者。然後跳轉首頁執行wx.login方法,登入成功,保持登陸狀態。

詳細流程:

步驟1:進入小程式首先通過wx.login獲取code,通過後臺介面發往後臺,後臺以此向微信API換取session_key和openid;

var user_phone = app.globalData.user_phone;
wx.login({
    success: res => {
      // 傳送 res.code 到後臺換取 openId, sessionKey, unionId
      wx.request({
        url: 'http://www.tphoutai.com/wx/index', 
        data: {
          code: res.code,
          user_phone: user_phone,
        },
        success: function
(result) {
var res = result.data; console.log(res); if(res.sendsure == 0){ wx.reLaunch({ url: '../login/login', }) }else if(res.sendsure == 1){ wx.reLaunch({ url: '../index/index', }) } } }) } })

步驟2:判斷資料庫中有無該openid【唯一標識,需和賬號(手機號)繫結】;

// 後臺程式碼:
public function index(Request $request){
        $url = "https://api.weixin.qq.com/sns/jscode2session";
        // 引數
        $params['appid']= '小程式的appid';
        $params['secret']= '小程式的AppSecret';
        $params['js_code']= $request -> param('code');
        $params['grant_type']= 'authorization_code';
        $user_phone= $request -> param('user_phone');

        // 微信API返回的session_key 和 openid
        $arr = httpWurl($url, $params, 'POST');
        $arr = json_decode($arr,true);
        // 判斷是否成功
        if(isset($arr['errcode']) && !empty($arr['errcode'])){
            return json(['code'=>'2','message'=>$arr['errmsg'],"result"=>null]);
        }
        $openid = $arr['openid'];
        $session_key = $arr['session_key'];

        // 從資料庫中查詢是否有該openid
        $is_openid = Db::table('user_info')->where('openid',$openid)->find();
        // 如果openid存在,更新openid_time,返回登入成功資訊及手機號
        if($is_openid){
            // openid存在,先判斷openid_time,與現在的時間戳相比,如果相差大於4個小時,則則返回登入失敗資訊,使客戶端跳轉登入頁,如果相差在四個小時之內,則更新openid_time,然後返回登入成功資訊及手機號;
            // 根據openid查詢到所在條資料
            $data = Db::table('user_info')->where('openid',$openid)->find();
            // 計算openid_time與現在時間的差值
            $time = time() - $data['openid_time'];
            $time = $time / 3600;
            // 如果四個小時沒更新過,則登陸態消失,返回失敗,重新登入
            if($time > 4){
                return json(['sendsure'=>'0','message'=>'登入失敗',]);
            }else{
                // 根據手機號更新openid時間
                $update = Db::table('user_info')->where('openid', $openid)->update(['openid_time' => time()]);

                // 判斷是否更新成功
                if($update){
                    return json(['sendsure'=>'1','message'=>'登入成功','user_phone' => $data['user_phone']]);
                }else{
                    return json(['sendsure'=>'0','message'=>'登入失敗']);
                }
            }
        // openid不存在時
        }else{
            // dump($user_phone);
            // 如果openid不存在, 判斷手機號是否為空
            if(isset($user_phone) && !empty($user_phone)){

                // 如果不為空,則說明是登入過的,就從資料庫中找到手機號,然後繫結openid,+時間

                // 登入後,手機號不為空,則根據手機號更新openid和openid_time
                $update = Db::table('user_info')
                    ->where('user_phone', $user_phone)
                    ->update([
                        'openid'  => $openid,
                        'openid_time' => time(),
                    ]);
                if($update){
                    return json(['sendsure'=>'1','message'=>'登入成功',]);
                }
            }else{
                // 如果也為空,則返回登入失敗資訊,使客戶端跳轉登入頁
                return json(['sendsure'=>'0','message'=>'讀取失敗',]);
            }
        }
    }

步驟3:登入頁面:登入成功後,跳轉首頁執行wx.login方法,然後登入成功,保持登陸狀態。

// 前臺登入
    wx.request({
      url: 'http://www.tphoutai.com/wx/login', 
      data: {
        user_phone: user_phone
      },
      success: function (result) {
        var res = result.data;

        if (res.sendsure == 1){
          app.globalData.user_phone = that.data.user_phone;
          wx.reLaunch({
            url: '../loading/loading',
          })
        }
      }
    })
// 後臺登入方法
    public function login(Request $request){

        // 獲取到前臺傳輸的手機號
        $user_phone = $request -> param('user_phone');
        // 判斷資料庫中該手機號是否存在
        $is_user_phone = Db::table('user_info')->where('user_phone',$user_phone)->find();
        if(isset($is_user_phone) && !empty($is_user_phone)){

            // 登入時,資料庫中存在該手機號,則更新openid_time
            $update = Db::table('user_info')
                    ->where('user_phone', $user_phone)
                    ->update([
                        'openid_time' => time(),
                    ]);
            if($update){
                return json(['sendsure'=>'1','message'=>'登入成功',]);
            }
        }else{
            $data = [
                "user_phone" => $user_phone,
                "pass" => '12345'
            ];
            // 如果資料庫中不存在該手機號,則進行新增
            Db::table('user_info')->insert($data);
        }
        return json(['sendsure'=>'1','message'=>'登入成功',]);
    }
根據微信API獲取sessionkey 和 openid的方法
function httpWurl($url, $params, $method = 'GET', $header = array(), $multi = false){
        date_default_timezone_set('PRC');
        $opts = array(
            CURLOPT_TIMEOUT        => 30,
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_HTTPHEADER     => $header,
            CURLOPT_COOKIESESSION  => true,
            CURLOPT_FOLLOWLOCATION => 1,
            CURLOPT_COOKIE         =>session_name().'='.session_id(),
        );
        /* 根據請求型別設定特定引數 */
        switch(strtoupper($method)){
            case 'GET':
                // $opts[CURLOPT_URL] = $url . '?' . http_build_query($params);
                // 連結後拼接引數  &  非?
                $opts[CURLOPT_URL] = $url . '?' . http_build_query($params);
                break;
            case 'POST':
                //判斷是否傳輸檔案
                $params = $multi ? $params : http_build_query($params);
                $opts[CURLOPT_URL] = $url;
                $opts[CURLOPT_POST] = 1;
                $opts[CURLOPT_POSTFIELDS] = $params;
                break;
            default:
                throw new Exception('不支援的請求方式!');
        }
        /* 初始化並執行curl請求 */
        $ch = curl_init();
        curl_setopt_array($ch, $opts);
        $data  = curl_exec($ch);
        $error = curl_error($ch);
        curl_close($ch);
        if($error) throw new Exception('請求發生錯誤:' . $error);
        return  $data;
    }

測試結果:
這裡寫圖片描述