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


授权流程:
- 用户在小程序中点击登录按钮,触发 wx.login()获取code。
- 小程序将 code发送到后端服务器。
- 后端通过微信接口 jscode2session使用code获取session_key和openid。
- 后端返回 session_key和openid给前端。
- 前端获取 session_key和openid,使用wx.getUserProfile()获取用户信息(如昵称、头像等)。
- 如果需要,可以将用户信息(如昵称、头像等)发送到后端进行存储或处理。
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) {
      
      
    }
  }
微信网页授权(OAuth 2.0)
网页授权是通过微信官方提供的OAuth2.0认证方式,使第三方网站或应用能够获取用户基本信息,实现用户身份识别。


授权流程
- 发起授权- 用户点击登录/授权按钮
- 生成授权链接
- 跳转至微信授权页面
 
- 用户确认
- 换取 Access Token- 服务端使用 code换取access_token
- 获取用户的 openid和access_token
 
- 获取用户信息- 使用 access_token和openid
- 调用微信接口获取用户详细信息
 
- 系统内部处理
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`;
  }
  
  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('获取用户信息失败');
    }
  }
}
微信开放平台授权

特点:
- 适用于第三方应用
- 支持移动应用、网站应用等
- 需要开发者资质认证
import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { firstValueFrom } from 'rxjs';
interface OpenPlatformAuthResponse {
  access_token: string;    
  expires_in: number;      
  refresh_token: string;   
  openid: string;          
  scope: string;           
  unionid: string;         
}
@Injectable()
export class OpenPlatformAuthService {
  constructor(private readonly httpService: HttpService) {}
  
  async getAccessToken(code: string): Promise<OpenPlatformAuthResponse> {
    
    const url = 'https://api.weixin.qq.com/sns/oauth2/access_token';
    
    try {
      
      const response = await firstValueFrom(
        this.httpService.get(url, {
          params: {
            
            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('开放平台授权失败');
    }
  }
  
  async refreshAccessToken(refreshToken: string) {
    
    const url = 'https://api.weixin.qq.com/sns/oauth2/refresh_token';
    
    try {
      
      const response = await firstValueFrom(
        this.httpService.get(url, {
          params: {
            
            appid: process.env.OPEN_PLATFORM_APPID,
            
            grant_type: 'refresh_token',
            
            refresh_token: refreshToken
          }
        })
      );
      return response.data;
    } catch (error) {
      
      throw new Error('刷新 Token 失败');
    }
  }
}
企业微信授权
企业微信授权是针对企业内部应用和员工的身份认证机制,提供更严格和精细的权限控制。


特点:
授权流程
- 发起授权- 员工访问企业内部应用
- 触发登录机制(扫码/输入)
- 生成企业微信授权链接
 
- 身份验证
- 换取用户信息- 服务端使用 code换取用户标识
- 获取 userid
- 调用接口获取用户详细信息
 
- 系统内部处理
import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { firstValueFrom } from 'rxjs';
interface EnterpriseWechatAuthResponse {
  access_token: string;    
  expires_in: number;      
  user_ticket?: string;    
  user_info?: {
    userid: string;        
    name: string;          
    department: number[];  
  };
}
@Injectable()
export class EnterpriseWechatAuthService {
  constructor(private readonly httpService: HttpService) {}
  
  async getUserInfo(code: string): Promise<EnterpriseWechatAuthResponse> {
    
    const tokenUrl = 'https://qyapi.weixin.qq.com/cgi-bin/gettoken';
    
    const userInfoUrl = 'https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo';
    
    
    const tokenResponse = await firstValueFrom(
      this.httpService.get(tokenUrl, {
        params: {
          
          corpid: process.env.ENTERPRISE_CORPID,
          
          corpsecret: process.env.ENTERPRISE_CORPSECRET
        }
      })
    );
    
    const accessToken = tokenResponse.data.access_token;
    
    const userInfoResponse = await firstValueFrom(
      this.httpService.get(userInfoUrl, {
        params: {
          
          access_token: accessToken,
          
          code: code
        }
      })
    );
    return userInfoResponse.data;
  }
}
各个平台授权小结
| 授权类型 | 个人是否可用 | 是否收费 | 主要适用场景 | 
|---|
| 网页授权 | 是 | 免费 | 网站、H5应用 | 
| 小程序授权 | 是 | 免费 | 小程序登录、开放平台 | 
| 公众号授权 | 部分可用 | 免费+增值服务 | 公众号相关应用(服务号、订阅号) | 
| 企业微信 | 否 | 有费用 | 企业内部协作 | 
转自https://www.cnblogs.com/HaiJun-Aion/p/18609286
该文章在 2024/12/17 15:49:13 编辑过