Skip to content

在对接微信小程序的时候,需要涉及到小程序的登录问题,下面是微信小程序开放者平台给提供的实现思路,流程如下:

实现的步骤 ​

下面是小程序使用的接口文档地址:

获取openId ​

前端在小程序中集成微信相关依赖,当用户请求登录的同时,调用wx.login() 获取 临时登录凭证code ,并回传到开发者服务器。如下:

js
wxLogin() {
  wx.login({
    success: (res) => {
      if (res.code) {
        // 拿到临时code,发给自己后端服务
        wx.request({
          url: 'https://你的后端接口地址/login',
          method: 'POST',
          data: {
            code: res.code
          },
          success: (resp) => {
            console.log('登录成功', resp.data);
            // 后端返回sessionId/token,存在storage后续请求携带
            wx.setStorageSync('token', resp.data.token);
          },
          fail: (err) => {
            console.error('请求后端失败', err);
          }
        })
      } else {
        console.log('获取code失败:', res.errMsg);
      }
    },
    fail: (err) => {
      console.error('wx.login调用失败', err);
    }
  })
}
实现如下:
java
package com.xhzb.nursing.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xhzb.common.exception.ServiceException;
import com.xhzb.framework.web.service.TokenService;
import com.xhzb.nursing.domain.FamilyMember;
import com.xhzb.nursing.domain.dto.member.MemberLoginDto;
import com.xhzb.nursing.domain.vo.MemberLoginVo;
import com.xhzb.nursing.service.IFamilyMemberService;
import com.xhzb.nursing.service.IMemberLoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 家属小程序登录Service业务层处理
 *
 * @author chengang
 * @date 2026-11-06
 */
@Service
public class MemberLoginServiceImpl implements IMemberLoginService
{
    /** 微信登录凭证校验接口 */
    private static final String CODE2SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session";

    /** 微信接口调用凭证接口 */
    private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";

    /** 微信获取手机号接口 */
    private static final String PHONE_NUMBER_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber";

    /** 昵称前缀集合 */
    private static final List<String> NICK_NAME_LIST = Arrays.asList(
            "大吉大利", "今晚吃鸡", "福星高照", "好事发生", "匆匆忙忙", "连滚带爬", "从从容容", "游刃有余");

    /** 小程序appId */
    @Value("${wechat.appId}")
    private String appid;

    /** 小程序appSecret */
    @Value("${wechat.appSecret}")
    private String secret;

    @Autowired
    private IFamilyMemberService familyMemberService;

    @Autowired
    private TokenService tokenService;

    /** 缓存的微信接口调用凭证 */
    private volatile String accessToken;

    /** 微信接口调用凭证过期时间戳 */
    private volatile long accessTokenExpireTime;

    /**
     * 调用微信code2Session接口换取openid
     *
     * @param code 临时登录凭证
     * @return openid
     */
    private String getOpenId(String code)
    {
        Map<String, Object> params = new HashMap<>();
        params.put("appid", appid);
        params.put("secret", secret);
        params.put("js_code", code);
        params.put("grant_type", "authorization_code");

        String body = HttpUtil.get(CODE2SESSION_URL, params);
        JSONObject result = JSONUtil.parseObj(body);
        checkWechatResult(result, "微信登录");

        String openId = result.getStr("openid");
        if (StrUtil.isBlank(openId))
        {
            throw new ServiceException("微信登录失败:未获取到openid");
        }
        return openId;
    }


    /**
     * 校验微信接口返回结果
     *
     * @param result 微信返回内容
     * @param action 操作名称
     */
    private void checkWechatResult(JSONObject result, String action)
    {
        Integer errcode = result.getInt("errcode");
        if (errcode != null && errcode != 0)
        {
            throw new ServiceException(action + "失败:" + result.getStr("errmsg"));
        }
    }
}

获取手机号 ​

前端代码如下:

js
handleGetPhone(e) {
  // 用户拒绝
  if (e.detail.errMsg !== 'getPhoneNumber:ok') {
    console.log('用户拒绝授权手机号', e.detail.errMsg)
    return
  }
  // ✅ 拿到手机号code,发给后端
  const phoneCode = e.detail.code
  wx.request({
    url: 'https://你的后端接口地址/getPhone',
    method: 'POST',
    data: {
      // 向后端传递phoneCode
      phoneCode: phoneCode
    },
    success(res) {
      console.log('手机号:', res.data.phoneNumber)
    },
    fail(err) {
      console.error('获取手机号失败', err)
    }
  })
}

先获取token,参考代码如下:

java
/**
 * 获取微信接口调用凭证,优先使用缓存
 *
 * @return access_token
 */
private synchronized String getAccessToken()
{
    long now = System.currentTimeMillis();
    if (StrUtil.isNotBlank(accessToken) && now < accessTokenExpireTime)
    {
        return accessToken;
    }

    Map<String, Object> params = new HashMap<>();
    params.put("grant_type", "client_credential");
    params.put("appid", appid);
    params.put("secret", secret);

    String body = HttpUtil.get(ACCESS_TOKEN_URL, params);
    JSONObject result = JSONUtil.parseObj(body);

    String token = result.getStr("access_token");
    if (StrUtil.isBlank(token))
    {
        throw new ServiceException("获取微信access_token失败:" + result.getStr("errmsg"));
    }

    // 提前5分钟失效,避免临界时间使用过期凭证
    long expiresIn = result.getLong("expires_in", 7200L);
    accessToken = token;
    accessTokenExpireTime = now + Math.max(expiresIn - 300, 0) * 1000;
    return token;
}

拿到token之后再来获取电话号码,代码参考如下:

java
package com.xhzb.nursing.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xhzb.common.exception.ServiceException;
import com.xhzb.framework.web.service.TokenService;
import com.xhzb.nursing.domain.FamilyMember;
import com.xhzb.nursing.domain.dto.member.MemberLoginDto;
import com.xhzb.nursing.domain.vo.MemberLoginVo;
import com.xhzb.nursing.service.IFamilyMemberService;
import com.xhzb.nursing.service.IMemberLoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 家属小程序登录Service业务层处理
 *
 * @author chengang
 * @date 2026-11-06
 */
@Service
public class MemberLoginServiceImpl implements IMemberLoginService
{
    /** 微信登录凭证校验接口 */
    private static final String CODE2SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session";

    /** 微信接口调用凭证接口 */
    private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";

    /** 微信获取手机号接口 */
    private static final String PHONE_NUMBER_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber";

    /** 昵称前缀集合 */
    private static final List<String> NICK_NAME_LIST = Arrays.asList(
            "大吉大利", "今晚吃鸡", "福星高照", "好事发生", "匆匆忙忙", "连滚带爬", "从从容容", "游刃有余");

    /** 小程序appId */
    @Value("${wechat.appId}")
    private String appid;

    /** 小程序appSecret */
    @Value("${wechat.appSecret}")
    private String secret;

    @Autowired
    private IFamilyMemberService familyMemberService;

    @Autowired
    private TokenService tokenService;

    /** 缓存的微信接口调用凭证 */
    private volatile String accessToken;

    /** 微信接口调用凭证过期时间戳 */
    private volatile long accessTokenExpireTime;

    /**
     * 调用微信getPhoneNumber接口获取手机号
     *
     * @param phoneCode 获取手机号的临时code
     * @return 手机号
     */
    private String getPhoneNumber(String phoneCode) {
        String url = PHONE_NUMBER_URL + "?access_token=" + getAccessToken();
        JSONObject param = JSONUtil.createObj().set("code", phoneCode);

        String body = HttpUtil.post(url, param.toString());
        JSONObject result = JSONUtil.parseObj(body);
        checkWechatResult(result, "获取手机号");

        JSONObject phoneInfo = result.getJSONObject("phone_info");
        String phone = phoneInfo == null ? null : phoneInfo.getStr("purePhoneNumber");
        if (StrUtil.isBlank(phone))
        {
            throw new ServiceException("获取手机号失败:未返回手机号");
        }
        return phone;
    }


    /**
     * 校验微信接口返回结果
     *
     * @param result 微信返回内容
     * @param action 操作名称
     */
    private void checkWechatResult(JSONObject result, String action) {
        Integer errcode = result.getInt("errcode");
        if (errcode != null && errcode != 0)
        {
            throw new ServiceException(action + "失败:" + result.getStr("errmsg"));
        }
    }
}