最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

微信授權(quán)小程序的完整步驟實例

 更新時間:2026年05月21日 11:24:15   作者:snow來了  
微信小程序是一種基于微信平臺的應(yīng)用程序,它可以在微信中直接使用,具有許多類似于原生應(yīng)用的功能,微信小程序添加授權(quán)登錄和用戶權(quán)限功能,我們可以使用微信提供的開放能力和API來實現(xiàn),這篇文章主要介紹了微信授權(quán)小程序的完整步驟,需要的朋友可以參考下

1. 登錄流程概述:

  • 前端通過 wx.login() 獲取臨時登錄憑證 code
  • 將 code 發(fā)送到后端服務(wù)器
  • 后端通過 code 換取用戶的 openid 和 session_key
  • 后端生成 JWT token 返回給前端
  • 前端存儲 token 用于后續(xù)請求的身份驗證

2. 前端登錄實現(xiàn):

wx.getUserProfile是微信專門用來獲取授權(quán)人信息的api,參數(shù)有2個:

  • 1是的desc,告訴接口你拿登錄信息做什么?

  • 2.success是拿到登錄信息以后要做什么,就是一個回調(diào)函數(shù)。

在回調(diào)函數(shù)里面做了2件事情:

  • 1.向本地服務(wù)發(fā)送登錄請求

  • 2.獲取到本地的token以后,緩存在本地

// 調(diào)用微信登錄
wx.login({
  success: (res) => {
    if (res.code) {
      // 獲取用戶信息
      wx.getUserProfile({
        desc: '用于完善會員資料',
        success: (userInfo) => {
          // 發(fā)送 code 和用戶信息到后端
          wx.request({
            url: 'api/user/login',
            method: 'POST',
            data: {
              code: res.code,
              userInfo: userInfo.userInfo
            },
            success: (loginRes) => {
              // 保存 token
              wx.setStorageSync('token', loginRes.data.token)
            }
          })
        }
      })
    }
  }
})

代碼拆開如下所示:

      const { code } = await new Promise((resolve, reject) => {
        wx.login({
          success: resolve,
          fail: reject
        });
      });

      // 2. 獲取用戶信息
      const userProfileRes = await new Promise((resolve, reject) => {
        wx.getUserProfile({
          desc: '用于完善會員資料',
          success: resolve,
          fail: reject
        });
      });

微信返回的數(shù)據(jù)如圖所示:

{
  userInfo: {
    nickName: "用戶昵稱",
    avatarUrl: "頭像URL",
    gender: 1,  // 性別 0:未知、1:男、2:女
    country: "國家",
    province: "省份",
    city: "城市",
    language: "zh_CN"  // 語言
  },
  rawData: "原始數(shù)據(jù)字符串",
  signature: "簽名",
  encryptedData: "加密數(shù)據(jù)",
  iv: "加密算法的初始向量"
}

wx.login會返回一個臨時的code,這個 code 不能直接用來識別用戶, 后端需要用這個 code 去微信服務(wù)器換取 openid 和 session_key, openid 才是用戶的真實唯一標(biāo)識。

也就是說在前端你用wx.login和wx.getUserProfile獲取到的信息,都是用戶公開信息,不能用來做用戶的唯一標(biāo)識,真正的唯一標(biāo)識是openid,還是得有小程序的后端代碼獲取。

3. 后端處理流程:

從代碼中可以看到,后端的登錄處理主要包含以下步驟:

在前端wx.login里面你拿到了用戶的臨時code,然后你通過本地后臺的'/user/login接口傳給后端,后端拿到你的code以后就會調(diào)用微信服務(wù),通過微信服務(wù)拿到sessionInfo里面的openid。

在你的數(shù)據(jù)庫User表里面一定有一個字段是openid,用來搜索用戶信息的。如果User里面有這個openId就說明它登錄了,沒有那就要后端把這個用戶及它的openid存到數(shù)據(jù)庫里面去。(用戶信息你可以通過前端和code一起傳過來)

// 調(diào)用微信登錄服務(wù)
const wechatService = new (require('../services/wechat'))();
const sessionInfo = await wechatService.code2Session(code);

if (!sessionInfo || !sessionInfo.openid) {
  throw new Error('獲取微信用戶信息失敗');
}

console.log('微信登錄成功,openId:', sessionInfo.openid);

// 查找或創(chuàng)建用戶
let user = await User.findOne({ where: { openId: sessionInfo.openid } });

4. 身份認(rèn)證機制:

微信用戶信息創(chuàng)建更新完以后,我們需要獲取token,這個件事也是在后端登錄接口里面做的。

4.1.后端獲取token

一般我們通過第三方庫拿到j(luò)wt實例,然后再去認(rèn)證token(身份令牌),比如在node服務(wù)里面,我們用的是jsonwebtoken

const jwt = require('jsonwebtoken');
  • 使用 JWT(JSON Web Token)進(jìn)行身份驗證:
// 生成JWT token
const token = jwt.sign(
  {
    userId: user.userId,   // 用戶ID
    openId: user.openId    // 微信openId
  },
  // 第二個參數(shù):密鑰
  process.env.JWT_SECRET || 'your_jwt_secret_key',
  // 第三個參數(shù):配置選項,7d表示: token有效期7天
  { expiresIn: process.env.JWT_EXPIRES_IN || '7d' }
);

在開發(fā)環(huán)境里面,JWT_SECRET一般是放在.env文件里面,就是一個向以下格式的字符串,我一般會執(zhí)行一個命令

node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

利用node自帶的crypto模塊幫我生成。

JWT格式

// JWT格式:header.payload.signature
// 例如:
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
// eyJ1c2VySWQiOjEsIm9wZW5JZCI6Im94eHh4IiwiaWF0IjoxNTE2MjM5MDIyfQ.
// SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

你只要設(shè)置了,jwt.sign()就可以根據(jù)JWT_SECRET創(chuàng)建出一個token出來。

那在正式環(huán)境里面JWT_SECRET怎么設(shè)置呢?

運維配置:
1.部署時通過運維工具(如 Docker、K8s、PM2)設(shè)置環(huán)境變量:
docker run -e JWT_SECRET=your_secure_key your-app

2.在代碼中讀取環(huán)境變量:
const token = jwt.sign(payload, process.env.JWT_SECRET);

用process.env.JWT_SECRET既可以拿到env里面配置信息,也能拿到運維配置信息

在線上環(huán)境里面,你想要安全系數(shù)更高,就3到6個月?lián)Q一次JWT_SECRET就好了。不管是線上,還是開發(fā)環(huán)境,我們都可以用node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"拿到一個唯一的JWT_SECRET。

小程序后端的login請求結(jié)束以后會把token返回出去

      ctx.body = {
        code: 200,
        message: '登錄成功',
        data: {
          token,
          userInfo: {
            userId: user.userId,
            nickName: user.nickName,
            avatarUrl: user.avatarUrl,
            phoneNumber: user.phoneNumber,
            openId: user.openId,
            balance: user.balance || 0,
            status: user.status,
            createTime: user.createTime,
            lastLoginTime: user.lastLoginTime
          }
        }
      };

4.2前端拿到token以后需要做的事情

前端拿到token要做三件事,1.緩存token,2.發(fā)送請求的時候把token帶上,3.后端api驗證token

4.2.1緩存token

在前端里面我們用const app = getApp();拿到小程序的全局變量,這個getApp都做了什么事情

// app.js
App({
  globalData: {
    userInfo: null,      // 用戶信息
    hasUserInfo: false,  // 是否已登錄
    token: null,         // 登錄token
    baseUrl: 'http://localhost:3000/api',  // API基礎(chǔ)地址
    selectedCategoryId: null  // 選中的分類ID
  },
  
  // 檢查登錄狀態(tài)
  checkLoginStatus() {
    try {
      const token = wx.getStorageSync('token');
      const userInfo = wx.getStorageSync('userInfo');
      
      if (token && userInfo) {
        this.globalData.token = token;
        this.globalData.userInfo = userInfo;
        this.globalData.hasUserInfo = true;
        return true;
      }
      return false;
    } catch (error) {
      return false;
    }
  },
  
  // 更新登錄狀態(tài)
  updateLoginStatus(token, userInfo) {
    if (token && userInfo) {
      this.globalData.token = token;
      this.globalData.userInfo = userInfo;
      this.globalData.hasUserInfo = true;
      wx.setStorageSync('token', token);
      wx.setStorageSync('userInfo', userInfo);
    } else {
      this.globalData.token = null;
      this.globalData.userInfo = null;
      this.globalData.hasUserInfo = false;
      wx.removeStorageSync('token');
      wx.removeStorageSync('userInfo');
    }
  }
})

最主要的就是

    wx.setStorageSync('token', token);
    wx.setStorageSync('userInfo', userInfo);

使用的時候就這樣:

const app = getApp();

// 1. 獲取全局?jǐn)?shù)據(jù)
const { userInfo, token } = app.globalData;

// 2. 調(diào)用全局方法
app.checkLoginStatus();
app.updateLoginStatus(token, userInfo);

在代碼里面一般這樣用,在進(jìn)入獲取用戶信息的時候用app.checkLoginStatus(),在登錄的時候用:app.updateLoginStatus(token, completeUserInfo);

// 獲取用戶信息時
getUserInfo() {
  // 從全局狀態(tài)獲取登錄信息
  const { hasUserInfo, userInfo } = app.globalData;
  
  if (hasUserInfo && userInfo) {
    // 使用全局?jǐn)?shù)據(jù)更新頁面
    this.setData({
      userInfo,
      hasUserInfo: true
    });
  } else {
    // 檢查登錄狀態(tài)
    const isLoggedIn = app.checkLoginStatus();
    // ...
  }
}

// 登錄成功時
// 6. 更新全局狀態(tài)
app.updateLoginStatus(token, completeUserInfo);

4.2.2請求帶上token

緩存本地token能干嘛?就是在請求后端接口的時候,從緩存里面拿到token,然后放到請求里面去

const token = wx.getStorageSync('token');
wx.request({
  url: 'api/xxx',
  header: {
    'Authorization': `Bearer ${token}`
  }
})

一般情況下,我們會在小程序項目里面有個請求攔截文件,進(jìn)行統(tǒng)一處理,所以你在請求api的時候一般看不到,如下:

4.2.3后端解析token,驗證身份

當(dāng)后端接收到請求以后,它會用jwt實例去解析token,token其實就是userId和openid的加密字符串。

// 當(dāng)收到請求時,后端會:
try {
  // 1. 從請求頭獲取 token
  const token = ctx.header.authorization?.split(' ')[1];
  
  // 2. 使用相同的密鑰驗證 token
  const decoded = jwt.verify(token, process.env.JWT_SECRET);
  
  // 3. 如果驗證成功,可以獲取到用戶信息
  const userId = decoded.userId;
  const openId = decoded.openId;
  
  // 4. 驗證失敗會拋出異常
} catch (err) {
  // token 無效或已過期
  ctx.throw(401, '無效的token');
}

如果你想知道token里面到底是什么就用免費的JWT解析器解析一下看看

4.2.4.退出登錄處理

前端微信刪除token,然后后端會更新用戶登錄狀態(tài)

// 前端清除本地存儲的token
wx.removeStorageSync('token')

// 后端更新用戶狀態(tài)
await User.update({
  updateTime: new Date()
}, {
  where: { userId }
});

5.利用心跳包來維護(hù)登錄狀態(tài)

5.1概念

心跳包就是前端有個接口,定時的向后端發(fā)送請求,讓服務(wù)器告訴我,我還活著沒有

// 心跳包就像人的心跳一樣,定期發(fā)送一個信號,表示"我還活著"
// 例如:每30秒發(fā)送一次請求
setInterval(() => {
  wx.request({
    url: '/api/heartbeat',
    method: 'POST',
    success: () => {
      console.log('心跳包發(fā)送成功');
    }
  });
}, 30000); // 30秒

具體的實現(xiàn)如下:

前端

// 在小程序中實現(xiàn)心跳機制
const startHeartbeat = () => {
  // 1. 首次連接
  sendHeartbeat();
  
  // 2. 定期發(fā)送
  const intervalId = setInterval(() => {
    sendHeartbeat();
  }, 30000);
  
  // 3. 保存定時器ID,以便可以停止
  wx.setStorageSync('heartbeatInterval', intervalId);
};

const sendHeartbeat = async () => {
  try {
    const res = await wx.request({
      url: 'api/user/heartbeat',
      method: 'POST',
      header: {
        'Authorization': `Bearer ${wx.getStorageSync('token')}`
      }
    });
    
    if (res.statusCode === 200) {
      console.log('心跳成功');
    } else {
      console.log('心跳失敗,可能需要重新登錄');
    }
  } catch (error) {
    console.error('心跳請求失敗:', error);
  }
};

// 在用戶登錄時啟動心跳
onLogin() {
  startHeartbeat();
}

// 在用戶退出時停止心跳
onLogout() {
  const intervalId = wx.getStorageSync('heartbeatInterval');
  if (intervalId) {
    clearInterval(intervalId);
  }
}

后端

// 在Redis中記錄用戶在線狀態(tài)
class UserController {
  static async heartbeat(ctx) {
    const userId = ctx.state.user.userId;
    
    // 使用Redis記錄用戶在線狀態(tài)
    await redis.setex(
      `user:online:${userId}`,  // key
      60,                       // 過期時間(秒)
      'online'                  // value
    );
    
    ctx.body = {
      code: 200,
      message: 'Heartbeat received'
    };
  }
  
  // 檢查用戶是否在線
  static async checkUserOnline(userId) {
    const status = await redis.get(`user:online:${userId}`);
    return status === 'online';
  }
}

這個機制的好處是:

  1. 實時性:可以及時發(fā)現(xiàn)用戶離線
  1. 可靠性:通過定期檢查確保連接狀態(tài)
  1. 靈活性:可以根據(jù)需求調(diào)整心跳頻率
  1. 安全性:可以及時清理過期的會話

缺點是:

  1. 需要額外的服務(wù)器資源
  1. 增加了網(wǎng)絡(luò)流量
  1. 需要考慮移動設(shè)備的電量消耗
  1. 需要處理網(wǎng)絡(luò)波動的情況

您覺得需要在項目中添加這個功能嗎?我可以幫您實現(xiàn)。

這個登錄認(rèn)證流程的優(yōu)點是:

  1. 使用微信官方的登錄機制,安全可靠
  1. 采用 JWT 進(jìn)行身份驗證,無需保存會話狀態(tài)
  1. token 有過期機制,增加安全性
  1. 支持自動創(chuàng)建新用戶和更新用戶信息
  1. 完整的錯誤處理和日志記錄

總結(jié) 

到此這篇關(guān)于微信授權(quán)小程序完整步驟的文章就介紹到這了,更多相關(guān)微信授權(quán)小程序內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 微信小程序 this.triggerEvent()的具體使用

    微信小程序 this.triggerEvent()的具體使用

    這篇文章主要介紹了微信小程序 this.triggerEvent()的具體使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • 鍵盤上一張下一張兼容IE/google/firefox等瀏覽器

    鍵盤上一張下一張兼容IE/google/firefox等瀏覽器

    鍵盤上一張下一張的效果想必大家都有見到過吧,本文為大家介紹的這個兼容IE,google,firefox等主流瀏覽器
    2014-01-01
  • 使用JavaScript實現(xiàn)二值化圖像

    使用JavaScript實現(xiàn)二值化圖像

    這篇文章主要為大家詳細(xì)介紹了使用JavaScript將圖像轉(zhuǎn)換為黑白二值圖的兩種方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-01-01
  • JS如何為promise增加abort功能

    JS如何為promise增加abort功能

    這篇文章主要介紹了JS為promise增加abort功能,想了解JS異步的同學(xué),可以參考下
    2021-04-04
  • javascript學(xué)習(xí)總結(jié)之js使用技巧

    javascript學(xué)習(xí)總結(jié)之js使用技巧

    本篇文章給大家分享javascript學(xué)習(xí)總結(jié)之js使用技巧,都是精華喔~小伙伴快來學(xué)習(xí)吧。
    2015-09-09
  • 面試官:說說Webpack和Vite有哪些區(qū)別

    面試官:說說Webpack和Vite有哪些區(qū)別

    Vite基于ESM實現(xiàn)按需編譯,開發(fā)啟動和熱更新速度極快,Webpack采用全量打包,適合復(fù)雜項目但啟動較慢,這篇文章主要介紹了Webpack和Vite有哪些區(qū)別的相關(guān)資料,需要的朋友可以參考下
    2026-04-04
  • 微信小程序?qū)崿F(xiàn)滑動切換自定義頁碼的方法分析

    微信小程序?qū)崿F(xiàn)滑動切換自定義頁碼的方法分析

    這篇文章主要介紹了微信小程序?qū)崿F(xiàn)滑動切換自定義頁碼的方法,結(jié)合實例形式分析了微信小程序頁碼動態(tài)切換相關(guān)實現(xiàn)技巧與注意事項,需要的朋友可以參考下
    2018-12-12
  • uni-app?中清除定時器實現(xiàn)方法詳解

    uni-app?中清除定時器實現(xiàn)方法詳解

    這篇文章主要為大家介紹了uni-app?中清除定時器實現(xiàn)方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • js實現(xiàn)小窗口拖拽效果

    js實現(xiàn)小窗口拖拽效果

    這篇文章主要為大家詳細(xì)介紹了js實現(xiàn)小窗口拖拽效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • 基于JS制作一個簡單的網(wǎng)頁版地圖

    基于JS制作一個簡單的網(wǎng)頁版地圖

    本文將利用JS實現(xiàn)一個簡單的網(wǎng)頁版地圖,這個簡單的網(wǎng)頁版地圖能根據(jù)城市名進(jìn)行位置查詢。文中的示例代碼講解詳細(xì),感興趣的可以了解一下
    2022-05-05

最新評論

罗甸县| 绍兴市| 中阳县| 黎平县| 综艺| 崇明县| 泰宁县| 太湖县| 松阳县| 宁城县| 洛南县| 康定县| 福安市| 长丰县| 山阴县| 西安市| 望城县| 内丘县| 镇安县| 福州市| 岢岚县| 南江县| 建瓯市| 巨鹿县| 红安县| 太仆寺旗| 于田县| 灵宝市| 牡丹江市| 桦川县| 内江市| 巴里| 米易县| 尚义县| 遂平县| 边坝县| 西乌珠穆沁旗| 广水市| 蓬溪县| 大荔县| 循化|