注:下面的都是用ai生成的,本人小菜鸡,只是记录学习,佬可以滑走
1. 前置准备:在微信开放平台 / 小程序后台配置
这一步是 “打通微信” 的前提,必须先完成:
- 注册并认证微信小程序账号(微信公众平台),获取 AppID 和 AppSecret(在 “开发 - 开发设置” 中查看)。
- 配置 “服务器域名”:在小程序后台 “开发 - 开发设置” 中,添加你的后端接口域名(如
https://api.yourapp.com),否则小程序无法请求你的后端。 - (可选)配置 “业务域名”:若有 H5 页面,需配置业务域名确保授权跳转正常。
2. 前端实现:发起登录请求,获取临时凭证
小程序端通过微信原生 API 获取 “临时登录凭证(code)”,再将 code 传给你的后端(注意:前端不直接处理用户信息,避免泄露敏感数据)。
javascript
运行
// 小程序前端代码(示例:点击“微信登录”按钮触发)
async function wechatLogin() {
try {
// 1. 调用微信 API 获取临时登录凭证 code(5分钟有效期,只能用一次)
const { code } = await wx.login({ timeout: 5000 });
if (!code) throw new Error("获取微信 code 失败");
// 2. 将 code 传给你的后端接口,请求自身应用的登录态(如 Token)
const res = await wx.request({
url: "https://api.yourapp.com/login/wechat", // 你的后端接口
method: "POST",
data: { code: code }, // 仅传 code,不处理其他信息
header: { "content-type": "application/json" }
});
// 3. 后端返回登录态后,存储到本地(如 wx.setStorage),用于后续接口请求
if (res.data.success) {
wx.setStorageSync("token", res.data.data.token);
wx.showToast({ title: "登录成功" });
// 跳转至首页或其他页面
}
} catch (err) {
wx.showToast({ title: "登录失败", icon: "none" });
console.error("微信登录异常:", err);
}
}
3.后端实现:核心逻辑 (处理 code -> 关联用户 -> 生成登录态)
后端是整个流程的核心,需完成“调用微信接口验证身份” “关联自身用户体系” “生成登录态” 三个关键动作,步骤如下:
3.1:用 code 向微信服务器换 access_token 和 OpenID
微信提供统一接口 https://api.weixin.qq.com/sns/jscode2session,传入你的 AppID、AppSecret、前端传来的 code,获取用户唯一标识 OpenID(每个用户在你的小程序中 OpenID 唯一,是关联用户的核心键)。
public class WechatLoginService {
@Value("${wechat.mini.appid}")
private String appId;
@Value("${wechat.mini.secret}")
private String appSecret;
// 1. 用 code 换微信的 session_key 和 OpenID
public WechatSessionDTO getWechatSession(String code) {
// 微信接口地址
String url = String.format(
"https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
appId, appSecret, code
);
// 调用微信接口(同步请求,实际项目建议用异步)
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
try (Response response = client.newCall(request).execute()) {
String responseBody = response.body().string();
// 解析微信返回的 JSON(包含 openid、session_key 等)
return new ObjectMapper().readValue(responseBody, WechatSessionDTO.class);
} catch (IOException e) {
throw new RuntimeException("调用微信接口失败", e);
}
}
// 省略其他方法...
}
}
@Data
public class WechatSessionDTO {
private String openid; // 用户唯一标识(核心)
private String session_key; // 微信会话密钥(用于解密用户信息,可选)
private String unionid; // 多平台统一标识(需微信账号认证后才有)
private Integer errcode; // 错误码(0 为成功)
private String errmsg; // 错误信息
}
步骤 3.2:关联自身用户体系(登录 / 注册逻辑)
拿到 OpenID 后,后端需判断该用户是否已在你的应用中注册:
- 若已注册:直接根据 OpenID 查询到自身应用的 “用户 ID”,生成登录态。
- 若未注册:自动创建新用户(用 OpenID 作为唯一标识,可后续补充昵称、头像等信息),再生成登录态。
java
运行
// 后端 Java 示例(用户关联逻辑)
@Service
public class UserService {
@Autowired
private UserMapper userMapper; // 操作自身用户表的 Mapper
@Autowired
private WechatLoginService wechatLoginService;
@Autowired
private RedisTemplate<String, String> redisTemplate;
// 2. 处理微信登录:关联用户 + 生成登录态
public LoginVO handleWechatLogin(String code) {
// 第一步:获取微信 OpenID
WechatSessionDTO sessionDTO = wechatLoginService.getWechatSession(code);
if (sessionDTO.getErrcode() != null && sessionDTO.getErrcode() != 0) {
throw new RuntimeException("微信授权失败:" + sessionDTO.getErrmsg());
}
String openid = sessionDTO.getOpenid();
if (openid == null) throw new RuntimeException("获取 OpenID 失败");
// 第二步:查询自身用户表,判断是否已注册
UserDO user = userMapper.selectByWechatOpenid(openid);
if (user == null) {
// 未注册:自动创建新用户(仅存 OpenID,后续可让用户完善信息)
user = new UserDO();
user.setWechatOpenid(openid);
user.setCreateTime(new Date());
user.setStatus(1); // 正常状态
userMapper.insert(user); // 插入数据库
}
// 第三步:生成自身应用的登录态(如 JWT Token 或 Redis Token)
String token = generateToken(user.getId());
// 返回登录结果(Token + 用户基本信息)
LoginVO loginVO = new LoginVO();
loginVO.setToken(token);
loginVO.setUserId(user.getId());
loginVO.setNickname(user.getNickname()); // 若有则返回,无则后续补充
return loginVO;
}
// 生成登录态(示例:用 Redis 存储 Token,有效期 7 天)
private String generateToken(Long userId) {
String token = UUID.randomUUID().toString().replace("-", "");
// 存储 Token 与用户ID的关联(key: token, value: userId,有效期 7 天)
redisTemplate.opsForValue().set(
"login:token:" + token,
userId.toString(),
7,
TimeUnit.DAYS
);
return token;
}
}
步骤 3.3:提供后端接口给前端调用
最后,后端需要暴露一个 HTTP 接口(如 /login/wechat),接收前端传来的 code,调用上述逻辑,返回登录态(Token)。
java
运行
// 后端 Controller 示例
@RestController
@RequestMapping("/login")
public class LoginController {
@Autowired
private UserService userService;
@PostMapping("/wechat")
public Result<LoginVO> wechatLogin(@RequestBody WechatLoginReq req) {
// 校验参数(code 不为空)
if (StringUtils.isEmpty(req.getCode())) {
return Result.fail("code 不能为空");
}
// 调用核心逻辑
LoginVO loginVO = userService.handleWechatLogin(req.getCode());
return Result.success(loginVO);
}
}
// 前端传入的请求参数模型
@Data
public class WechatLoginReq {
private String code; // 前端传来的微信临时登录凭证
}
// 后端返回的登录结果模型
@Data
public class LoginVO {
private String token; // 自身应用的登录态
private Long userId; // 自身应用的用户ID
private String nickname; // 用户昵称(可选)
}
4. 关键注意事项(避坑点)
- 敏感信息不暴露:AppSecret 必须存在后端,绝对不能放在前端(小程序 / APP/H5),否则会被反编译窃取,导致账号被盗用。
- access_token 缓存:微信返回的 access_token 有有效期(通常 2 小时),后端需用 Redis 缓存,避免重复请求微信接口(微信对接口调用有频率限制)。
- 用户信息解密(可选) :若需要获取用户昵称、头像等信息,小程序前端需调用
wx.getUserProfile()获取加密数据,后端用session_key解密(需注意:微信自 2022 年起,用户信息需用户主动授权,且头像昵称可能是匿名的)。 - 多平台统一(UnionID) :若你的应用有 “小程序”“APP”“网站” 多个端,需在微信开放平台认证账号,获取 UnionID(同一用户在你的多个端 UnionID 唯一),实现多端账号统一。
- 登录态安全:自身应用的 Token 需设置有效期,支持刷新 Token(避免用户频繁登录),同时需校验 Token 合法性(如每次接口请求都验证 Token 是否在 Redis 中存在)。