微信登录接入指南

⚠️ 重要提示:没有企业怎么办?

问题

微信开放平台的网站应用需要企业认证,个人开发者无法申请。

解决方案

方案一:暂时跳过微信登录(推荐)
  • ✅ 先实现其他登录方式:手机号登录QQ登录微博登录
  • ✅ 这些登录方式对个人开发者更友好
  • ✅ 等有企业资质后再接入微信登录
  • 💡 建议:先实现手机号登录,这是最通用的登录方式
方案二:使用微信公众平台(需要公众号)
  • 注册并认证公众号(订阅号免费,服务号需认证)
  • 使用网页授权获取用户信息
  • ⚠️ 限制:需要用户关注公众号,体验不如开放平台
方案三:使用第三方登录服务
  • 使用 Authing、Auth0 等第三方服务
  • 优点:无需企业认证,快速接入
  • 缺点:可能有费用,依赖第三方
方案四:使用测试环境(仅开发测试)
  • 使用微信开放平台提供的测试账号
  • ⚠️ 仅用于开发测试,不能用于生产环境

一、准备工作

1. 注册微信开放平台账号

  • 访问:https://open.weixin.qq.com/
  • 注册并完成企业认证(个人开发者无法创建网站应用)
  • 认证费用:300元/年
  • ⚠️ 如果没有企业,请参考上方的解决方案

2. 创建网站应用

  1. 登录微信开放平台
  2. 进入"管理中心" -> “网站应用” -> “创建网站应用”
  3. 填写应用信息:
    • 应用名称
    • 应用简介
    • 应用官网
    • 应用图标
  4. 获取关键信息:
    • AppID(应用ID)
    • AppSecret(应用密钥)

3. 配置授权回调域名

  • 在应用详情页设置"授权回调域名"
  • 例如:yourdomain.com(不需要加协议和路径)
  • 注意:只能设置一个域名,且必须是已备案的域名

二、微信登录流程

流程图

用户点击微信登录
    ↓
跳转到微信授权页面
    ↓
用户授权后,微信回调到你的网站(带code参数)
    ↓
前端将code发送给后端
    ↓
后端用code换取access_token
    ↓
后端用access_token获取用户信息
    ↓
后端处理登录逻辑,返回token给前端
    ↓
前端保存token,完成登录

三、前端实现

1. 添加微信登录API方法

src/api/auth.js 中添加:

// 微信登录 - 获取授权URL
getWechatAuthUrl: () => {
  const appId = process.env.REACT_APP_WECHAT_APPID; // 从环境变量读取
  const redirectUri = encodeURIComponent(
    `${window.location.origin}/login/wechat/callback`
  );
  const state = Math.random().toString(36).substring(7); // 防止CSRF攻击
  localStorage.setItem('wechat_state', state);
  
  return `https://open.weixin.qq.com/connect/qrconnect?appid=${appId}&redirect_uri=${redirectUri}&response_type=code&scope=snsapi_login&state=${state}#wechat_redirect`;
},

// 微信登录 - 用code换取token
wechatLogin: async (code, state) => {
  try {
    const { data } = await axios.post('/productx/user/wechat-login', {
      code,
      state
    });
    
    if (data.success) {
      const token = data.data.token;
      localStorage.setItem('token', token);
      axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
      
      // 获取用户信息
      const userInfoResult = await auth.getUserInfo();
      if (!userInfoResult.success) {
        return { success: false, message: '获取用户信息失败' };
      }
      
      return { success: true };
    }
    return data;
  } catch (error) {
    return { 
      success: false, 
      message: error.response?.data?.message || '微信登录失败' 
    };
  }
}

2. 添加微信登录按钮点击事件

src/pages/Login/components/RightSection/index.js 中:

import { auth } from '../../../../api/auth';
import { useNavigate } from 'react-router-dom';

export const RightSection = ({
  // ... 其他props
  locale
}) => {
  const navigate = useNavigate();
  
  // 处理微信登录
  const handleWechatLogin = () => {
    const authUrl = auth.getWechatAuthUrl();
    window.location.href = authUrl; // 跳转到微信授权页面
  };

  // ... 其他代码

  return (
    // ... 其他JSX
    <SocialButton 
      type="button" 
      socialType="wechat" 
      index={0} 
      title="微信登录"
      onClick={handleWechatLogin}
    >
      <SiWechat />
    </SocialButton>
    // ... 其他JSX
  );
};

3. 创建微信登录回调页面

创建 src/pages/Login/WechatCallback.js

import React, { useEffect } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { message } from 'antd';
import { auth } from '../../api/auth';

const WechatCallback = () => {
  const navigate = useNavigate();
  const [searchParams] = useSearchParams();
  
  useEffect(() => {
    const handleCallback = async () => {
      const code = searchParams.get('code');
      const state = searchParams.get('state');
      const savedState = localStorage.getItem('wechat_state');
      
      // 验证state,防止CSRF攻击
      if (!state || state !== savedState) {
        message.error('登录失败:状态验证失败');
        navigate('/login');
        return;
      }
      
      // 清除保存的state
      localStorage.removeItem('wechat_state');
      
      if (!code) {
        message.error('登录失败:未获取到授权码');
        navigate('/login');
        return;
      }
      
      // 显示加载提示
      message.loading('正在登录...', 0);
      
      try {
        const result = await auth.wechatLogin(code, state);
        
        if (result.success) {
          message.destroy();
          message.success('登录成功');
          navigate('/workspace');
        } else {
          message.destroy();
          message.error(result.message || '登录失败');
          navigate('/login');
        }
      } catch (error) {
        message.destroy();
        message.error('登录失败,请稍后重试');
        navigate('/login');
      }
    };
    
    handleCallback();
  }, [searchParams, navigate]);
  
  return (
    <div style={{ 
      display: 'flex', 
      justifyContent: 'center', 
      alignItems: 'center', 
      height: '100vh' 
    }}>
      <div>正在处理微信登录...</div>
    </div>
  );
};

export default WechatCallback;

4. 添加路由

src/App.js 中添加:

import WechatCallback from './pages/Login/WechatCallback';

// 在Routes中添加
<Route path="/login/wechat/callback" element={<WechatCallback />} />

5. 配置环境变量

在项目根目录创建 .env 文件(如果还没有):

REACT_APP_WECHAT_APPID=你的微信AppID

四、后端实现

1. 后端接口:/productx/user/wechat-login

请求参数:

{
  "code": "微信返回的授权码",
  "state": "防止CSRF的状态码"
}

后端处理流程:

// 伪代码示例(Node.js/Express)

app.post('/productx/user/wechat-login', async (req, res) => {
  const { code, state } = req.body;
  const appId = process.env.WECHAT_APPID;
  const appSecret = process.env.WECHAT_APPSECRET;
  
  try {
    // 1. 用code换取access_token
    const tokenResponse = await axios.get(
      `https://api.weixin.qq.com/sns/oauth2/access_token`,
      {
        params: {
          appid: appId,
          secret: appSecret,
          code: code,
          grant_type: 'authorization_code'
        }
      }
    );
    
    const { access_token, openid, unionid } = tokenResponse.data;
    
    if (!access_token) {
      return res.json({
        success: false,
        message: '获取access_token失败'
      });
    }
    
    // 2. 用access_token获取用户信息
    const userInfoResponse = await axios.get(
      `https://api.weixin.qq.com/sns/userinfo`,
      {
        params: {
          access_token: access_token,
          openid: openid
        }
      }
    );
    
    const { nickname, headimgurl, sex, province, city } = userInfoResponse.data;
    
    // 3. 根据openid或unionid查找或创建用户
    let user = await User.findOne({ 
      $or: [
        { wechatOpenId: openid },
        { wechatUnionId: unionid }
      ]
    });
    
    if (!user) {
      // 创建新用户
      user = await User.create({
        username: `wx_${openid.substring(0, 8)}`,
        nickname: nickname,
        avatar: headimgurl,
        wechatOpenId: openid,
        wechatUnionId: unionid,
        gender: sex === 1 ? 'male' : sex === 2 ? 'female' : 'unknown',
        province: province,
        city: city,
        loginType: 'wechat'
      });
    } else {
      // 更新用户信息
      user.nickname = nickname;
      user.avatar = headimgurl;
      user.lastLoginAt = new Date();
      await user.save();
    }
    
    // 4. 生成JWT token
    const token = generateToken(user);
    
    // 5. 返回token
    res.json({
      success: true,
      data: {
        token: token,
        user: {
          id: user._id,
          username: user.username,
          nickname: user.nickname,
          avatar: user.avatar
        }
      }
    });
    
  } catch (error) {
    console.error('微信登录错误:', error);
    res.json({
      success: false,
      message: '微信登录失败'
    });
  }
});

2. 数据库用户表字段

需要在用户表中添加以下字段:

  • wechatOpenId - 微信OpenID(唯一标识)
  • wechatUnionId - 微信UnionID(跨应用统一标识,可选)
  • loginType - 登录方式(‘email’, ‘wechat’, 'qq’等)

五、注意事项

1. 安全性

  • ✅ 必须验证 state 参数,防止CSRF攻击
  • AppSecret 必须保存在后端,不能暴露在前端
  • ✅ 使用HTTPS协议
  • ✅ 验证回调URL的域名

2. 用户体验

  • ✅ 登录成功后自动跳转到目标页面
  • ✅ 显示加载状态,避免用户重复点击
  • ✅ 错误提示要友好

3. 错误处理

  • 用户取消授权:微信会返回 error 参数
  • code过期:code只能使用一次,且5分钟内有效
  • 网络错误:需要重试机制

4. 测试

  • 使用微信开放平台提供的测试账号
  • 在本地开发时,可以使用内网穿透工具(如ngrok)来测试回调

六、常见问题

Q1: 回调域名必须备案吗?

A: 是的,微信要求回调域名必须是已备案的域名。

Q2: 本地开发如何测试?

A: 可以使用内网穿透工具(如ngrok、natapp)将本地地址映射到公网域名。

Q3: UnionID和OpenID的区别?

A:

  • OpenID:同一用户在不同应用中的标识不同
  • UnionID:同一用户在同一开发者账号下的所有应用中标识相同
  • 建议同时保存UnionID,方便多应用统一用户体系

Q4: 如何实现微信扫码登录?

A: 使用 qrconnect 接口(本指南已使用),会自动显示二维码。如果是PC端,可以显示二维码让用户扫码。


七、参考文档

  • 微信开放平台文档:https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html
  • 微信登录接口文档:https://developers.weixin.qq.com/doc/oplatform/en/Website_App/WeChat_Login/Wechat_Login.html
Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐