微信授权全链路打通指南

小程序数据库云存储

picture.image

近期,我在致力于打造自己的小程序产品时,迎来了一项关键性的进展——微信相关授权流程 的完整实现。从用户登录到权限获取,我们细致入微地梳理并实现了每一项授权机制,确保了用户体验的流畅与安全。

后端代码采用的是Nest 提供的伪代码,整体思路已提供。

微信小程序授权

picture.image

picture.image

授权流程:

  1. 用户在小程序中点击登录按钮,触发 wx.login() 获取 code
  2. 小程序将 code 发送到后端服务器。
  3. 后端通过微信接口 jscode2session 使用 code 获取 session\_keyopenid
  4. 后端返回 session\_keyopenid 给前端。
  5. 前端获取 session\_keyopenid ,使用 wx.getUserProfile() 获取用户信息(如昵称、头像等)。
  6. 如果需要,可以将用户信息(如昵称、头像等)发送到后端进行存储或处理。
  
wx.login({ success: function(res) { if (res.code) { // 将 code 发送到服务器 wx.request({ url: 'https://localhost:8080/api/login', method: 'POST', data: { code: res.code }, success: function(response) { // 处理服务器返回的数据 console.log(response.data); } }); } } });

下面是Nest 伪代码实现

  
import { Injectable } from '@nestjs/common';  
import { HttpService } from '@nestjs/axios';  
import { firstValueFrom } from 'rxjs';  
  
interface MiniProgramLoginResponse {  
  openid: string;  
  session\_key: string;  
  unionid?: string;  
  errcode?: number;  
  errmsg?: string;  
}  
  
@Injectable()  
  export class MiniProgramAuthService {  
    constructor(private readonly httpService: HttpService) {}  
  
    async login(code: string): Promise<MiniProgramLoginResponse> {  
      const url = 'https://api.weixin.qq.com/sns/jscode2session';  
  
      try {  
        const response = await firstValueFrom(  
          this.httpService.get(url, {  
            params: {  
              appid: process.env.MINIPROGRAM\_APPID,  
              secret: process.env.MINIPROGRAM\_APPSECRET,  
              js\_code: code,  
              grant\_type: 'authorization\_code'  
            }  
          })  
        );  
  
        return response.data;  
      } catch (error) {  
        throw new Error('小程序登录失败');  
      }  
    }  
  
    // 解密用户敏感信息  
    async decryptUserInfo(sessionKey: string, encryptedData: string, iv: string) {  
      // 实现微信小程序用户信息解密逻辑  
      // 通常需要使用第三方加密库如 crypto-js  
    }  
  }  

微信网页授权(OAuth 2.0)

网页授权是通过微信官方提供的OAuth2.0认证方式,使第三方网站或应用能够获取用户基本信息,实现用户身份识别。

picture.image

picture.image

授权流程

  1. 发起授权
  • 用户点击登录/授权按钮
  • 生成授权链接
  • 跳转至微信授权页面
  • 用户确认
  • 用户选择是否授权
  • 确认后获取临时授权码 code
  • 换取 Access Token
  • 服务端使用 code 换取 access\_token
  • 获取用户的 openidaccess\_token
  • 获取用户信息
  • 使用 access\_tokenopenid
  • 调用微信接口获取用户详细信息
  • 系统内部处理
  • 创建或更新用户信息
  • 生成系统内部登录态
  
import { Injectable } from '@nestjs/common';  
import { HttpService } from '@nestjs/axios';  
import { firstValueFrom } from 'rxjs';  
  
// 用户授权信息接口定义  
interface WechatUserInfo {  
  openid: string;      // 用户唯一标识  
  nickname: string;    // 用户昵称  
  sex: number;         // 用户性别  
  province: string;    // 省份  
  city: string;        // 城市  
  country: string;     // 国家  
  headimgurl: string;  // 头像地址  
  privilege: string[]; // 用户特权信息  
  unionid?: string;    // 开放平台唯一标识  
}  
  
@Injectable()  
export class WebAuthService {  
  constructor(private readonly httpService: HttpService) {}  
  
  // 生成授权链接  
  generateAuthUrl(redirectUri: string, scope: 'snsapi\_base' | 'snsapi\_userinfo' = 'snsapi\_userinfo') {  
    const baseUrl = 'https://open.weixin.qq.com/connect/oauth2/authorize';  
    const params = new URLSearchParams({  
      appid: process.env.WECHAT\_APPID,  
      redirect\_uri: redirectUri,  
      response\_type: 'code',  
      scope: scope,  
      state: 'STATE#wechat\_redirect'  // 自定义参数,用于回传  
    });  
      
    return `${baseUrl}?${params}#wechat\_redirect`;  
  }  
  
  // 获取 Access Token  
  async getAccessToken(code: string) {  
    const url = 'https://api.weixin.qq.com/sns/oauth2/access\_token';  
      
    try {  
      const response = await firstValueFrom(  
        this.httpService.get(url, {  
          params: {  
            appid: process.env.WECHAT\_APPID,  
            secret: process.env.WECHAT\_APPSECRET,  
            code: code,  
            grant\_type: 'authorization\_code'  
          }  
        })  
      );  
  
      return response.data;  
    } catch (error) {  
      throw new Error('获取 Access Token 失败');  
    }  
  }  
  
  // 获取用户信息  
  async getUserInfo(accessToken: string, openid: string): Promise<WechatUserInfo> {  
    const url = 'https://api.weixin.qq.com/sns/userinfo';  
      
    try {  
      const response = await firstValueFrom(  
        this.httpService.get(url, {  
          params: {  
            access\_token: accessToken,  
            openid: openid,  
            lang: 'zh\_CN'  
          }  
        })  
      );  
  
      return response.data;  
    } catch (error) {  
      throw new Error('获取用户信息失败');  
    }  
  }  
}  

微信开放平台授权

picture.image

特点:

  • 适用于第三方应用
  • 支持移动应用、网站应用等
  • 需要开发者资质认证
  
import { Injectable } from '@nestjs/common';  
import { HttpService } from '@nestjs/axios';  
import { firstValueFrom } from 'rxjs';  
  
// 定义开放平台授权响应接口  
interface OpenPlatformAuthResponse {  
  access\_token: string;    // 接口调用凭证  
  expires\_in: number;      // access\_token 过期时间  
  refresh\_token: string;   // 刷新 token  
  openid: string;          // 授权用户唯一标识  
  scope: string;           // 用户授权的作用域  
  unionid: string;         // 开放平台唯一标识  
}  
  
@Injectable()  
export class OpenPlatformAuthService {  
  constructor(private readonly httpService: HttpService) {}  
  
  /**  
   * 获取 access\_token  
   * @param code 授权码  
   * @returns 授权响应信息  
   */  
  async getAccessToken(code: string): Promise<OpenPlatformAuthResponse> {  
    // 微信获取 access\_token 的接口地址  
    const url = 'https://api.weixin.qq.com/sns/oauth2/access\_token';  
      
    try {  
      // 使用授权码换取 access\_token  
      const response = await firstValueFrom(  
        this.httpService.get(url, {  
          params: {  
            // 从环境变量读取开放平台 AppID  
            appid: process.env.OPEN\_PLATFORM\_APPID,  
            // 从环境变量读取开放平台密钥  
            secret: process.env.OPEN\_PLATFORM\_APPSECRET,  
            // 授权码  
            code: code,  
            // 授权类型,固定值  
            grant\_type: 'authorization\_code'  
          }  
        })  
      );  
  
      return response.data;  
    } catch (error) {  
      // 捕获并抛出授权失败的错误  
      throw new Error('开放平台授权失败');  
    }  
  }  
  
  /**  
   * 刷新 access\_token  
   * @param refreshToken 刷新 token  
   * @returns 新的授权信息  
   */  
  async refreshAccessToken(refreshToken: string) {  
    // 微信刷新 access\_token 的接口地址  
    const url = 'https://api.weixin.qq.com/sns/oauth2/refresh\_token';  
      
    try {  
      // 使用 refresh\_token 换取新的 access\_token  
      const response = await firstValueFrom(  
        this.httpService.get(url, {  
          params: {  
            // 开放平台 AppID  
            appid: process.env.OPEN\_PLATFORM\_APPID,  
            // 授权类型,固定值  
            grant\_type: 'refresh\_token',  
            // 用于刷新的 token  
            refresh\_token: refreshToken  
          }  
        })  
      );  
  
      return response.data;  
    } catch (error) {  
      // 捕获并抛出刷新 Token 失败的错误  
      throw new Error('刷新 Token 失败');  
    }  
  }  
}  

企业微信授权

企业微信授权是针对企业内部应用和员工的身份认证机制,提供更严格和精细的权限控制。

picture.image

picture.image

特点:

  • 主要面向企业内部应用
  • 更强的权限控制
  • 安全性更高

授权流程

  1. 发起授权
  • 员工访问企业内部应用
  • 触发登录机制(扫码/输入)
  • 生成企业微信授权链接
  • 身份验证
  • 跳转企业微信登录页
  • 员工确认身份
  • 获取临时授权码
  • 换取用户信息
  • 服务端使用 code 换取用户标识
  • 获取 userid
  • 调用接口获取用户详细信息
  • 系统内部处理
  • 验证员工身份
  • 检查权限状态
  • 生成系统内部登录态
  
import { Injectable } from '@nestjs/common';  
import { HttpService } from '@nestjs/axios';  
import { firstValueFrom } from 'rxjs';  
  
// 定义企业微信授权响应接口  
interface EnterpriseWechatAuthResponse {  
  access\_token: string;    // 企业接口调用凭证  
  expires\_in: number;      // access\_token 过期时间  
  user\_ticket?: string;    // 用户票据(可选)  
  user\_info?: {  
    userid: string;        // 企业成员 ID  
    name: string;          // 成员名称  
    department: number[];  // 部门 ID 列表  
  };  
}  
  
@Injectable()  
export class EnterpriseWechatAuthService {  
  constructor(private readonly httpService: HttpService) {}  
  
  /**  
   * 获取企业微信用户信息  
   * @param code 临时授权码  
   * @returns 用户信息和 access\_token  
   */  
  async getUserInfo(code: string): Promise<EnterpriseWechatAuthResponse> {  
    // 获取企业 access\_token 的接口地址  
    const tokenUrl = 'https://qyapi.weixin.qq.com/cgi-bin/gettoken';  
    // 获取用户信息的接口地址  
    const userInfoUrl = 'https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo';  
  
    // 第一步:获取企业 access\_token  
    // 需要使用企业 ID 和应用的秘钥  
    const tokenResponse = await firstValueFrom(  
      this.httpService.get(tokenUrl, {  
        params: {  
          // 从环境变量读取企业 ID  
          corpid: process.env.ENTERPRISE\_CORPID,  
          // 从环境变量读取企业应用秘钥  
          corpsecret: process.env.ENTERPRISE\_CORPSECRET  
        }  
      })  
    );  
  
    // 从响应中提取 access\_token  
    const accessToken = tokenResponse.data.access\_token;  
  
    // 第二步:使用 access\_token 和临时授权码获取用户信息  
    const userInfoResponse = await firstValueFrom(  
      this.httpService.get(userInfoUrl, {  
        params: {  
          // 企业 access\_token  
          access\_token: accessToken,  
          // 临时授权码  
          code: code  
        }  
      })  
    );  
  
    return userInfoResponse.data;  
  }  
}  

各个平台授权小结

| 授权类型 | 个人是否可用 | 是否收费 | 主要适用场景 | | --- | --- | --- | --- | | 网页授权 | 是 | 免费 | 网站、H5应用 | | 小程序授权 | 是 | 免费 | 小程序登录、开放平台 | | 公众号授权 | 部分可用 | 免费+增值服务 | 公众号相关应用(服务号、订阅号) | | 企业微信 | 否 | 有费用 | 企业内部协作 |

0
0
0
0
关于作者
关于作者

文章

0

获赞

0

收藏

0

相关资源
DevOps 在字节移动研发中的探索和实践
在日益复杂的APP工程架构下,如何保证APP能高效开发,保障团队效能和工程质量?本次将结合字节内部应用的事件案例,介绍DevOps团队对移动研发效能建设的探索和思考。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论