Skip to content

GitLab

  • Projects
  • Groups
  • Snippets
  • Help
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
T treasure
  • Project overview
    • Project overview
    • Details
    • Activity
    • Releases
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 12
    • Issues 12
    • List
    • Boards
    • Labels
    • Service Desk
    • Milestones
  • Merge requests 0
    • Merge requests 0
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Operations
    • Operations
    • Incidents
    • Environments
  • Packages & Registries
    • Packages & Registries
    • Container Registry
  • Analytics
    • Analytics
    • CI/CD
    • Repository
    • Value Stream
  • Wiki
    • Wiki
  • External wiki
    • External wiki
  • Snippets
    • Snippets
  • Members
    • Members
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • FE
  • treasure
  • Issues
  • #135

Closed
Open
Created Mar 07, 2023 by chenyu@CubiDeveloper

前端接入微信登录授权方案

小程序登录流程时序图.drawio 如图为官方提供流程流程时序图,较为复杂。

实际为通过微信提供的getPhoneNumbe 方法拿到iv,encryptedData ,与用wx.login() 方法获取的code。传给服务端。服务端需要在后台服务器调用code2Session,使用code换取openid、unionid、session_key等系信息,解密iv,encryptedData ,从而获得手机号。

服务端登录之后把token和手机号返回给前端,缓存后下次token失效可以直接用手机号登录。

登录按钮

由于微信更新了用户隐私规范,授权窗口只能通过规定的按钮由用户点击触发,无法通过api的方式调起,所以我们需要封装一个登录按钮。

注意:1、在回调中调用 wx.login 登录,可能会刷新登录态。此时服务器使用 code 换取的 sessionKey 不是加密时使用的 sessionKey,导致解密失败。

2、wx.login()获取的code只有5分钟有效期,如果用户在获取手机号五分钟后点击登录会失效。

所以在点击获取手机号的时候调wx.login()

import { BaseEventOrig, Button, ButtonProps } from "@tarojs/components";
import React, { useState } from "react";
import Taro from "@tarojs/taro";
import { getLoginCode } from "@/common/api/user";
import { miniProgramAuthLogin } from "@/common/api/login";

// LoginButton.ts
const LoginButton = React.memo((props: any) => {
  const { children, onSuccess, onClick, ...other } = props;
  const [code, setCode] = useState("");

  const handleGetPhoneNumber = async (
    e: BaseEventOrig<ButtonProps.onGetPhoneNumberEventDetail>
  ) => {
    console.log('e.detail ', e.detail)
    const { iv, encryptedData, errMsg } = e.detail;
    try {
      if (!code) {
        // 实际上是调用了wx.Login()
        getLoginCode().then((wxCode: any) => {
          Taro.showToast({ title: wxCode });
          setCode(wxCode);
          if (errMsg.includes("ok")) {
            Taro.showLoading({ title: "正在登录" });
            miniProgramAuthLogin({
              iv,
              encryptedData,
              loginCode: wxCode,
              getMobileCode: e.detail.code
            }).then(res => {
              Taro.hideLoading();
              onSuccess?.(res);
              Taro.showToast({ title: '登录成功' });
            });
          }
        });
      }
    } catch (error) {
      // 解密失败重新login
      getLoginCode().then((wxCode: any) => {
        setCode(wxCode);
      });
      Taro.hideLoading();
      Taro.showToast({ title: error.message || error.errMsg });
    }
  };
  const handleBtnClick = async (event) => {
    onClick?.(event);
  };


  return (
    <>
      <Button
        openType="getPhoneNumber" // 用于将 code 换取用户手机号
        onClick={handleBtnClick}
        onGetPhoneNumber={handleGetPhoneNumber}
        {...other}
      >
        {children}
      </Button>
    </>
  );
});

export default LoginButton;

登录方法

import Taro from "@tarojs/taro";
// 使用promise封装微信开放接口login

export const getLoginCode = () => {
  return new Promise((resolve, reject) => {
    Taro.login({
      success: function (res) {
        if (res.code) {
          resolve(res.code)
        } else {
          console.log('登录失败!' + res.errMsg)
          reject(res)
        }
      }
    })
  })
}

业务流程图 业务流程图

Assignee
Assign to
None
Milestone
None
Assign milestone
Time tracking