You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 04:07:04