微信小程序登录

43 阅读5分钟

注:下面的都是用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. 关键注意事项(避坑点)

  1. 敏感信息不暴露:AppSecret 必须存在后端,绝对不能放在前端(小程序 / APP/H5),否则会被反编译窃取,导致账号被盗用。
  2. access_token 缓存:微信返回的 access_token 有有效期(通常 2 小时),后端需用 Redis 缓存,避免重复请求微信接口(微信对接口调用有频率限制)。
  3. 用户信息解密(可选) :若需要获取用户昵称、头像等信息,小程序前端需调用 wx.getUserProfile() 获取加密数据,后端用 session_key 解密(需注意:微信自 2022 年起,用户信息需用户主动授权,且头像昵称可能是匿名的)。
  4. 多平台统一(UnionID) :若你的应用有 “小程序”“APP”“网站” 多个端,需在微信开放平台认证账号,获取 UnionID(同一用户在你的多个端 UnionID 唯一),实现多端账号统一。
  5. 登录态安全:自身应用的 Token 需设置有效期,支持刷新 Token(避免用户频繁登录),同时需校验 Token 合法性(如每次接口请求都验证 Token 是否在 Redis 中存在)。