Strapi v4对接自定义手机号OTP认证系统的实现方案问询
在Strapi v4中对接自定义OTP认证系统
以下是实现对接自定义Node.js OTP认证系统、替换默认登录/注册流程的具体步骤:
1. 扩展用户模型,添加手机号字段
Strapi默认用户模型没有手机号字段,需要先扩展模型:
编辑src/api/user/content-types/user/schema.json,在attributes中添加手机号配置:
{ "attributes": { "phone": { "type": "string", "required": true, "unique": true, "minLength": 10, "maxLength": 15 }, // 保留原有name、email、password等字段 } }
修改后重启Strapi,让模型生效。
2. 创建自定义认证控制器
重写Strapi的认证控制器,添加OTP发送和验证逻辑。创建/编辑src/api/auth/controllers/auth.js:
const axios = require('axios'); module.exports = { // 发送OTP接口(支持注册+登录场景) async sendOtp(ctx) { const { phone, name } = ctx.request.body; // 检查用户是否存在,不存在则创建新用户 let user = await strapi.db.query('plugin::users-permissions.user').findOne({ where: { phone } }); if (!user) { // 生成临时密码(Strapi用户必须有密码字段) const tempPassword = Math.random().toString(36).slice(-8); user = await strapi.db.query('plugin::users-permissions.user').create({ data: { phone, name: name || '', password: tempPassword, confirmed: false // 未验证OTP前不激活用户 } }); } // 调用自定义OTP系统API发送验证码 try { await axios.post('http://你的OTP服务器地址/api/send-otp', { phone: user.phone }); ctx.send({ message: 'OTP已发送至你的手机号' }); } catch (error) { ctx.badRequest('发送OTP失败,请稍后重试'); } }, // 验证OTP并生成Strapi JWT async verifyOtp(ctx) { const { phone, otp } = ctx.request.body; // 校验用户是否存在 const user = await strapi.db.query('plugin::users-permissions.user').findOne({ where: { phone } }); if (!user) { return ctx.badRequest('用户不存在'); } // 调用自定义OTP系统验证验证码 try { const verifyRes = await axios.post('http://你的OTP服务器地址/api/verify-otp', { phone, otp }); if (!verifyRes.data.valid) { return ctx.badRequest('OTP验证码无效或已过期'); } // 激活未验证的用户 if (!user.confirmed) { await strapi.db.query('plugin::users-permissions.user').update({ where: { id: user.id }, data: { confirmed: true } }); } // 生成Strapi标准JWT令牌 const jwtToken = strapi.service('plugin::users-permissions.jwt').issue({ id: user.id }); // 返回JWT和用户信息 ctx.send({ jwt: jwtToken, user: { id: user.id, phone: user.phone, name: user.name } }); } catch (error) { ctx.badRequest('验证OTP失败,请稍后重试'); } }, // 可选:禁用默认密码登录(如果不需要) async login(ctx) { return ctx.badRequest('请使用手机号OTP登录'); } };
3. 配置自定义路由
创建/编辑src/api/auth/routes/auth.js,添加OTP相关接口路由:
module.exports = { routes: [ { method: 'POST', path: '/auth/send-otp', handler: 'auth.sendOtp', config: { auth: false, policies: [] } }, { method: 'POST', path: '/auth/verify-otp', handler: 'auth.verifyOtp', config: { auth: false, policies: [] } }, // 保留或修改默认登录路由 { method: 'POST', path: '/auth/login', handler: 'auth.login', config: { auth: false, policies: [] } } ] };
4. 配置公共权限
在Strapi后台进入Settings > Users & Permissions Plugin > Roles > Public,找到Auth模块,勾选send-otp和verify-otp的权限,保存设置。
关键注意事项
- 临时密码处理:Strapi用户模型强制要求密码字段,所以生成随机临时密码即可,后续登录无需使用该密码。
- OTP系统安全:确保自定义OTP API使用HTTPS传输,设置合理的OTP过期时间(如5分钟)和错误重试次数限制。
- 错误优化:可以根据自定义OTP API的返回码,细化错误提示(如"OTP已过期"、"验证次数过多"等)。
- 扩展字段支持:如果需要用户注册时提交更多信息(如姓名),直接在
sendOtp接口中接收并写入用户数据即可。
内容的提问来源于stack exchange,提问作者SHAHNAWAZ HUSSAIN
相关产品推荐
相关产品推荐

