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

实现的步骤
下面是小程序使用的接口文档地址:
获取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"));
}
}
}