微信小程序登錄流程

1. 前言

  1. 登錄很簡(jiǎn)單,基本都做過,但是進(jìn)行總結(jié)的可能不多
  2. 今天閑來無事就總結(jié)一波

2. 登錄方式

  1. 微信小程序的登錄流程分為兩種情況
  2. 一種是使用微信開放平臺(tái)登錄
  3. 一種是使用自定義登錄方式

3. 使用微信開放平臺(tái)登錄

  1. 用戶在小程序中點(diǎn)擊登錄按鈕队丝,觸發(fā)登錄事件卧土。
  2. 小程序調(diào)用wx.login()方法獲取臨時(shí)登錄憑證code。
  3. 小程序調(diào)用 wx.getUserInfo()方法獲取用戶的基本信息(頭像雕欺、昵稱等)盒齿。
  4. 小程序?qū)?code>code和用戶信息發(fā)送給開發(fā)者的后臺(tái)服務(wù)器阿宅。
  5. 開發(fā)者的后臺(tái)服務(wù)器使用 AppIDAppSecret 調(diào)用微信接口獲取 session_key 和 openid橡类。
  6. 開發(fā)者的后臺(tái)服務(wù)器使用session_key對(duì)用戶信息進(jìn)行解密接谨,獲取用戶的真實(shí)信息摆碉。
  7. 開發(fā)者的后臺(tái)服務(wù)器將用戶的信息存儲(chǔ)到數(shù)據(jù)庫(kù)中,并生成一個(gè)自定義登錄態(tài)token并返回給小程序脓豪。
  8. 小程序保存該自定義登錄態(tài)token巷帝,并在以后的請(qǐng)求中帶上該token

4. 相關(guān)代碼

  1. 客戶端授權(quán)登錄
// 點(diǎn)擊按鈕觸發(fā)登錄事件
wx.login({
  success: res => {
    // 獲取臨時(shí)登錄憑證
    const code = res.code;
    // 獲取用戶信息
    wx.getUserInfo({
      success: res => {
        const userInfo = res.userInfo;
        // 將 code 和 userInfo 發(fā)送給后臺(tái)服務(wù)器
        wx.request({
          url: 'https://xx.xx.com/api/login',
          data: {
            code: code,
            userInfo: userInfo
          },
          success: res => {
            // 將服務(wù)器返回的自定義登錄態(tài) token 存儲(chǔ)到本地
            wx.setStorageSync('token', res.data.token);
          }
        });
      }
    });
  }
});

  1. 后臺(tái)服務(wù)器處理登錄邏輯
const request = require('request');
const crypto = require('crypto');

const APP_ID = '你的 app id';
const APP_SECRET = '你的 app secret';

// 處理小程序端登錄請(qǐng)求
function login(req, res) {
  const code = req.body.code;
  const userInfo = req.body.userInfo;

  // 獲取 session_key 和 openid
  request(`https://api.weixin.qq.com/sns/jscode2session?appid=${APP_ID}&secret=${APP_SECRET}&js_code=${code}&grant_type=authorization_code`, function(error, response, body) {
    const result = JSON.parse(body);
    const session_key = result.session_key;
    const openid = result.openid;

    // 使用 session_key 對(duì)用戶信息進(jìn)行解密
    const encryptedData = userInfo.encryptedData;
    const iv = userInfo.iv;
    const decipher = crypto.createDecipheriv('aes-128-cbc', new Buffer(session_key, 'base64'), new Buffer(iv, 'base64'));
    let decoded = decipher.update(encryptedData, 'base64', 'utf8');
    decoded += decipher.final('utf8');
    const userInfoObj = JSON.parse(decoded);

    // 將用戶信息存儲(chǔ)到數(shù)據(jù)庫(kù)中扫夜,生成自定義登錄態(tài) token 并返回
    const token = generateToken(userInfoObj);
    res.json({ token: token });
  });
}

// 生成自定義登錄態(tài) token
function generateToken(userInfo) {
  const secret = 'your secret key';
  const expireTime = new Date().getTime() + 24 * 3600 * 1000;
  const data = JSON.stringify({
    userInfo: userInfo,
    expireTime: expireTime
  });
  const hash = crypto.createHmac('sha256', secret).update(data).digest('hex');
  const token = `${data}.${hash}`;
  return token;
}

只是大概流程 沒有考慮用戶退出登錄楞泼、token 過期等其他情況的處理。


5. 自定義登錄方式

  1. 用戶在小程序中輸入賬號(hào)密碼笤闯,點(diǎn)擊“登錄”按鈕堕阔,觸發(fā)登錄事件。
  2. 小程序?qū)⒂脩糨斎氲馁~號(hào)密碼發(fā)送給開發(fā)者的后臺(tái)服務(wù)器颗味。
  3. 開發(fā)者的后臺(tái)服務(wù)器根據(jù)賬號(hào)密碼驗(yàn)證用戶的身份超陆,并生成一個(gè)自定義登錄態(tài)token并返回給小程序。
  4. 小程序保存該自定義登錄態(tài) token浦马,并在以后的請(qǐng)求中帶上該token时呀。
  1. 需要注意的是张漂,在使用自定義登錄方式時(shí),為了保障用戶數(shù)據(jù)的安全谨娜,需要使用 HTTPS 協(xié)議鹃锈,并對(duì)用戶密碼進(jìn)行加密傳輸和存儲(chǔ)

6. 相關(guān)代碼

  1. 客戶端登錄邏輯
// 自定義登錄函數(shù),使用用戶名和密碼登錄
const login = (username, password) => {
  return new Promise((resolve, reject) => {
    wx.request({
      url: 'https://xx.yzs.com/api/login',
      method: 'POST',
      data: {
        username: username,
        password: password
      },
      success: res => {
        // 將服務(wù)器返回的自定義登錄態(tài) token 存儲(chǔ)到本地
        wx.setStorageSync('token', res.data.token);
        resolve(res.data);
      },
      fail: err => {
        reject(err);
      }
    });
  });
};

// 在登錄頁面中調(diào)用 login 函數(shù)進(jìn)行登錄
const handleLogin = () => {
  const username = '密碼';
  const password = '用戶名';
  login(username, password).then(res => {
    // 登錄成功瞧预,跳轉(zhuǎn)到首頁
    wx.redirectTo({
      url: '/pages/home/index',
    });
  }).catch(err => {
    // 登錄失敗屎债,提示錯(cuò)誤信息
    wx.showToast({
      title: '登錄失敗,請(qǐng)重試垢油!',
      icon: 'none'
    });
  });
};
  1. 后臺(tái)相關(guān)邏輯
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const crypto = require('crypto');

app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

// 處理自定義登錄請(qǐng)求
app.post('/api/login', (req, res) => {
  const username = req.body.username;
  const password = req.body.password;

  // 根據(jù)用戶名和密碼查詢用戶信息
  const user = getUserByUsernameAndPassword(username, password);
  if (!user) {
    res.status(401).json({ message: '用戶名或密碼錯(cuò)誤盆驹!' });
    return;
  }

  // 將用戶信息存儲(chǔ)到數(shù)據(jù)庫(kù)中,生成自定義登錄態(tài) token 并返回
  const token = generateToken(user);
  res.json({ token: token });
});

// 生成自定義登錄態(tài) token
const generateToken = user => {
  const secret = '自己的secret key';
  const expireTime = new Date().getTime() + 24 * 3600 * 1000;
  const data = JSON.stringify({
    userId: user.id,
    expireTime: expireTime
  });
  const hash = crypto.createHmac('sha256', secret).update(data).digest('hex');
  const token = `${data}.${hash}`;
  return token;
};

// 根據(jù)用戶名和密碼查詢用戶信息
const getUserByUsernameAndPassword = (username, password) => {
  // TODO: 實(shí)現(xiàn)根據(jù)用戶名和密碼查詢用戶信息的邏輯
  return {
    id: 123,
    username: 'testuser',
    nickname: 'Test User'
  };
};

app.listen(3000, () => {
  console.log('Server started on port 3000.');
});


7. 請(qǐng)求配置 token

  1. 核心代碼
// 假設(shè) token 存在于本地緩存中滩愁,緩存的鍵名為 'token'
const token = wx.getStorageSync('token')

wx.request({
  url: 'https://xx.com/api/some-resource',
  header: {
    'Authorization': `Bearer ${token}`
  },
  success(res) {
    console.log(res.data)
  },
  fail(err) {
    console.error(err)
  }
})
  1. 通過 wx.getStorageSync() 方法獲取本地緩存中存儲(chǔ)的 token躯喇,
  2. 然后將其添加到header對(duì)象中的 Authorization 屬性中,值為 Bearer ${token}硝枉,
  3. 其中 Bearer 為固定字符串廉丽,${token}是變量,表示真正的 token 值妻味。
  4. 最終發(fā)送的請(qǐng)求頭會(huì)包含Authorization: Bearer ${token}正压,其中 ${token} 會(huì)被替換為真實(shí)的 token 值。

參考資料


初心

我所有的文章都只是基于入門责球,初步的了解焦履;是自己的知識(shí)體系梳理,如有錯(cuò)誤,道友們一起溝通交流;
如果能幫助到有緣人,非常的榮幸,一切為了部落的崛起;
共勉
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市雏逾,隨后出現(xiàn)的幾起案子嘉裤,更是在濱河造成了極大的恐慌,老刑警劉巖栖博,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件屑宠,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡仇让,警方通過查閱死者的電腦和手機(jī)典奉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來妹孙,“玉大人秋柄,你說我怎么就攤上這事获枝〈勒” “怎么了?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵省店,是天一觀的道長(zhǎng)嚣崭。 經(jīng)常有香客問我笨触,道長(zhǎng),這世上最難降的妖魔是什么雹舀? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任芦劣,我火速辦了婚禮,結(jié)果婚禮上说榆,老公的妹妹穿的比我還像新娘虚吟。我一直安慰自己,他們只是感情好签财,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布串慰。 她就那樣靜靜地躺著,像睡著了一般唱蒸。 火紅的嫁衣襯著肌膚如雪邦鲫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天神汹,我揣著相機(jī)與錄音庆捺,去河邊找鬼。 笑死屁魏,一個(gè)胖子當(dāng)著我的面吹牛滔以,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播氓拼,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼醉者,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了披诗?” 一聲冷哼從身側(cè)響起撬即,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎呈队,沒想到半個(gè)月后剥槐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宪摧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年粒竖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片几于。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蕊苗,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出沿彭,到底是詐尸還是另有隱情朽砰,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站瞧柔,受9級(jí)特大地震影響漆弄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜造锅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一撼唾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧哥蔚,春花似錦倒谷、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至倍靡,卻和暖如春猴伶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背塌西。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工他挎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人捡需。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓办桨,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親站辉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子呢撞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容