我来介绍一下如何实现 OpenClaw 的一键登录功能。一键登录通常指通过短信验证码或第三方授权快速登录的方式

openclaw OpenClaw手册 4

短信验证码一键登录方案

前端实现(HTML/JS 示例)

<!-- 登录页面 -->
<div class="login-container">
    <input type="tel" id="phone" placeholder="请输入手机号" maxlength="11">
    <div class="code-section">
        <input type="text" id="code" placeholder="请输入验证码" maxlength="6">
        <button id="sendCodeBtn" onclick="sendCode()">获取验证码</button>
    </div>
    <button id="loginBtn" onclick="quickLogin()">一键登录</button>
</div>
<script>
// 发送验证码
async function sendCode() {
    const phone = document.getElementById('phone').value;
    if (!/^1[3-9]\d{9}$/.test(phone)) {
        alert('请输入正确的手机号');
        return;
    }
    const btn = document.getElementById('sendCodeBtn');
    btn.disabled = true;
    let count = 60;
    // 发送验证码请求
    try {
        const response = await fetch('/api/send-code', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({ phone })
        });
        if (response.ok) {
            // 开始倒计时
            const timer = setInterval(() => {
                btn.textContent = `${count}秒后重新发送`;
                count--;
                if (count <= 0) {
                    clearInterval(timer);
                    btn.textContent = '获取验证码';
                    btn.disabled = false;
                }
            }, 1000);
        }
    } catch (error) {
        console.error('发送验证码失败:', error);
        btn.disabled = false;
    }
}
// 一键登录
async function quickLogin() {
    const phone = document.getElementById('phone').value;
    const code = document.getElementById('code').value;
    if (!phone || !code) {
        alert('请填写完整信息');
        return;
    }
    try {
        const response = await fetch('/api/quick-login', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({ phone, code })
        });
        const result = await response.json();
        if (result.success) {
            // 登录成功,保存 token 并跳转
            localStorage.setItem('token', result.token);
            window.location.href = '/dashboard';
        } else {
            alert(result.message || '登录失败');
        }
    } catch (error) {
        console.error('登录失败:', error);
    }
}
</script>

后端实现(Node.js 示例)

// server.js
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();
app.use(express.json());
// 存储验证码(生产环境建议使用 Redis)
const codeStore = new Map();
// 发送验证码
app.post('/api/send-code', async (req, res) => {
    const { phone } = req.body;
    // 生成6位随机验证码
    const code = Math.floor(100000 + Math.random() * 900000).toString();
    // 存储验证码,设置5分钟过期
    codeStore.set(phone, {
        code,
        expires: Date.now() + 5 * 60 * 1000
    });
    // 调用短信服务商 API(示例:阿里云)
    await sendSMSCode(phone, code);
    res.json({ success: true, message: '验证码已发送' });
});
// 一键登录验证
app.post('/api/quick-login', (req, res) => {
    const { phone, code } = req.body;
    // 验证验证码
    const stored = codeStore.get(phone);
    if (!stored || stored.code !== code) {
        return res.status(400).json({ 
            success: false, 
            message: '验证码错误' 
        });
    }
    if (Date.now() > stored.expires) {
        codeStore.delete(phone);
        return res.status(400).json({ 
            success: false, 
            message: '验证码已过期' 
        });
    }
    // 验证通过,生成 JWT token
    const token = jwt.sign(
        { phone, userId: generateUserId() },
        process.env.JWT_SECRET,
        { expiresIn: '7d' }
    );
    // 清理验证码
    codeStore.delete(phone);
    // 创建或获取用户
    const user = findOrCreateUser(phone);
    res.json({
        success: true,
        token,
        user
    });
});
// 短信发送函数(阿里云示例)
async function sendSMSCode(phone, code) {
    const SMSClient = require('@alicloud/sms-sdk');
    const smsClient = new SMSClient({
        accessKeyId: process.env.ALI_ACCESS_KEY,
        secretAccessKey: process.env.ALI_SECRET_KEY
    });
    return smsClient.sendSMS({
        PhoneNumbers: phone,
        SignName: 'OpenClaw',
        TemplateCode: 'SMS_123456789',
        TemplateParam: `{"code":"${code}"}`
    });
}

第三方登录(以微信为例)

前端实现

<!-- 微信登录按钮 -->
<button id="wechatLogin" onclick="wechatLogin()">
    <img src="wechat-icon.png" alt="微信登录">
    微信一键登录
</button>
<script>
function wechatLogin() {
    // 跳转到微信授权页面
    const appId = 'your_wechat_app_id';
    const redirectUri = encodeURIComponent(`${window.location.origin}/auth/callback`);
    const state = generateState();
    const authUrl = `https://open.weixin.qq.com/connect/qrconnect?appid=${appId}&redirect_uri=${redirectUri}&response_type=code&scope=snsapi_login&state=${state}`;
    window.location.href = authUrl;
}
</script>

后端微信登录处理

// 微信登录回调处理
app.get('/auth/callback', async (req, res) => {
    const { code } = req.query;
    if (!code) {
        return res.redirect('/login?error=auth_failed');
    }
    try {
        // 1. 获取 access_token
        const tokenResponse = await axios.get('https://api.weixin.qq.com/sns/oauth2/access_token', {
            params: {
                appid: process.env.WECHAT_APP_ID,
                secret: process.env.WECHAT_APP_SECRET,
                code,
                grant_type: 'authorization_code'
            }
        });
        const { access_token, openid } = tokenResponse.data;
        // 2. 获取用户信息
        const userResponse = await axios.get('https://api.weixin.qq.com/sns/userinfo', {
            params: {
                access_token,
                openid,
                lang: 'zh_CN'
            }
        });
        const userInfo = userResponse.data;
        // 3. 创建或更新本地用户
        const user = await findOrCreateUserByWechat({
            openid: userInfo.openid,
            nickname: userInfo.nickname,
            avatar: userInfo.headimgurl,
            unionid: userInfo.unionid
        });
        // 4. 生成 JWT token
        const token = jwt.sign(
            { userId: user.id, openid: user.openid },
            process.env.JWT_SECRET,
            { expiresIn: '7d' }
        );
        // 5. 重定向到前端,携带 token
        res.redirect(`/auth/success?token=${token}`);
    } catch (error) {
        console.error('微信登录失败:', error);
        res.redirect('/login?error=wechat_failed');
    }
});

安全增强措施

// 1. 添加频率限制
const rateLimit = require('express-rate-limit');
const loginLimiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15分钟
    max: 5, // 最多5次尝试
    message: '尝试次数过多,请稍后再试'
});
app.use('/api/quick-login', loginLimiter);
// 2. 验证码安全
function generateSecureCode() {
    return crypto.randomInt(100000, 999999).toString();
}
// 3. IP限制
app.use('/api/send-code', (req, res, next) => {
    const ip = req.ip;
    const today = new Date().toDateString();
    const key = `${ip}:${today}`;
    const count = ipStore.get(key) || 0;
    if (count > 20) {
        return res.status(429).json({
            success: false,
            message: '今日发送次数已达上限'
        });
    }
    ipStore.set(key, count + 1);
    next();
});

一键登录最佳实践

  1. 用户体验优化

    我来介绍一下如何实现 OpenClaw 的一键登录功能。一键登录通常指通过短信验证码或第三方授权快速登录的方式-第1张图片-OpenClaw 开源免费 -中文免费安装

    • 添加自动填充手机号功能
    • 支持回车键提交
    • 添加加载状态提示
  2. 错误处理完善

    try {
        // 登录逻辑
    } catch (error) {
        if (error.response?.status === 429) {
            showError('操作过于频繁,请稍后再试');
        } else if (error.code === 'NETWORK_ERROR') {
            showError('网络连接失败,请检查网络');
        } else {
            showError('登录失败,请重试');
        }
    }
  3. 移动端适配

    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <input type="tel" pattern="[0-9]*" inputmode="numeric">

需要根据你的具体技术栈和业务需求进行调整,如果你有特定的技术框架(如 React、Vue 等)或具体的业务场景需求,我可以提供更针对性的代码示例。

标签: OpenClaw 一键登录

抱歉,评论功能暂时关闭!