短信验证码一键登录方案
前端实现(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();
});
一键登录最佳实践
-
用户体验优化

- 添加自动填充手机号功能
- 支持回车键提交
- 添加加载状态提示
-
错误处理完善
try { // 登录逻辑 } catch (error) { if (error.response?.status === 429) { showError('操作过于频繁,请稍后再试'); } else if (error.code === 'NETWORK_ERROR') { showError('网络连接失败,请检查网络'); } else { showError('登录失败,请重试'); } } -
移动端适配
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <input type="tel" pattern="[0-9]*" inputmode="numeric">
需要根据你的具体技术栈和业务需求进行调整,如果你有特定的技术框架(如 React、Vue 等)或具体的业务场景需求,我可以提供更针对性的代码示例。
版权声明:除非特别标注,否则均为本站原创文章,转载时请以链接形式注明文章出处。