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

Strapi自定义更新用户端点未在角色权限面板显示的问题排查

问题描述

尝试扩展Strapi的users-permissions插件,添加一个更新用户信息的自定义端点updateMe,但新端点未出现在后台面板的「设置/用户与权限插件/角色/已认证用户/用户权限/user」区域中。

操作步骤

  1. 在src/extensions/users-permissions/目录下创建strapi-server.js,代码如下:
const _ = require("lodash");
const utils = require("@strapi/utils");
const { ApplicationError, ValidationError } = utils.errors;

module.exports = (plugin) => {
  plugin.controllers.user.updateMe = async (ctx) => {
    // 需要登录验证
    if (!ctx.state.user || !ctx.state.user.id) {
      throw new ApplicationError("You need to be logged");
    }

    if (
      !_.has(ctx.request.body, "username") ||
      ctx.request.body.username === ""
    ) {
      throw new ValidationError("Invalid data");
    }
    const allowedProperties = ["username"];
    const bodyKeys = Object.keys(ctx.request.body);
    if (bodyKeys.filter((key) => !allowedProperties.includes(key)).length > 0) {
      throw new ValidationError("Invalid data");
    }

    const newBody = {};
    bodyKeys.map(
      (key) =>
        (newBody[key] = ctx.request.body[key].trim().replace(/[<>]/g, ""))
    );
    if (_.has(ctx.request.body, "username")) {
      const userWithSameUsername = await strapi
        .query("plugin::users-permissions.user")
        .findOne({ where: { username: ctx.request.body.username } });
      if (
        userWithSameUsername &&
        _.toString(userWithSameUsername.id) !== _.toString(ctx.state.user.id)
      ) {
        throw new ApplicationError("Username already taken");
      }
    }

    await strapi
      .query("plugin::users-permissions.user")
      .update({
        where: { id: ctx.state.user.id },
        data: newBody,
      })
      .then((res) => {
        ctx.response.body = { username: res.username };
        ctx.response.status = 200;
      });
  };

  plugin.routes["content-api"].routes.push({
    method: "PUT",
    path: "/user/me",
    handler: "user.updateMe",
    config: {
      prefix: "",
      policies: [],
    },
  });

  return plugin;
};
  1. 在config/plugins.js中注册插件:
module.exports = ({ env }) => ({
  email: {
    config: {
      provider: "nodemailer",
      providerOptions: {
        host: env("SMTP_HOST"),
        port: env("SMTP_PORT"),
        auth: {
          user: env("SMTP_USER"),
          pass: env("SMTP_PASS"),
        },
      },
      settings: {
        defaultFrom: env("SMTP_DEFAULT_FROM"),
        defaultReplyTo: env("SMTP_DEFAULT_REPLYTO"),
      },
    },
  },
  "users-permissions": {
    enabled: true,
    resolve: "./src/extensions/users-permissions",
  },
});

服务正常启动,但后台权限面板中找不到updateMe权限选项,当前使用Strapi版本为4.24.4,降级会引发其他问题。


解决方案

Strapi 4.20+版本对自定义路由的权限配置做了调整,需要显式添加权限元数据才能在后台面板显示对应的权限选项。修改strapi-server.js,补充权限注册逻辑:

修改后的完整代码:

const _ = require("lodash");
const utils = require("@strapi/utils");
const { ApplicationError, ValidationError } = utils.errors;

module.exports = (plugin) => {
  // 保留原控制器逻辑
  plugin.controllers.user.updateMe = async (ctx) => {
    if (!ctx.state.user || !ctx.state.user.id) {
      throw new ApplicationError("请先登录");
    }

    if (
      !_.has(ctx.request.body, "username") ||
      ctx.request.body.username === ""
    ) {
      throw new ValidationError("数据无效");
    }
    const allowedProperties = ["username"];
    const bodyKeys = Object.keys(ctx.request.body);
    if (bodyKeys.filter((key) => !allowedProperties.includes(key)).length > 0) {
      throw new ValidationError("数据无效");
    }

    const newBody = {};
    bodyKeys.map(
      (key) =>
        (newBody[key] = ctx.request.body[key].trim().replace(/[<>]/g, ""))
    );
    if (_.has(ctx.request.body, "username")) {
      const userWithSameUsername = await strapi
        .query("plugin::users-permissions.user")
        .findOne({ where: { username: ctx.request.body.username } });
      if (
        userWithSameUsername &&
        _.toString(userWithSameUsername.id) !== _.toString(ctx.state.user.id)
      ) {
        throw new ApplicationError("用户名已被占用");
      }
    }

    const updatedUser = await strapi
      .query("plugin::users-permissions.user")
      .update({
        where: { id: ctx.state.user.id },
        data: newBody,
      });

    ctx.response.body = { username: updatedUser.username };
    ctx.response.status = 200;
  };

  // 修改路由配置,添加权限范围
  plugin.routes["content-api"].routes.push({
    method: "PUT",
    path: "/user/me",
    handler: "user.updateMe",
    config: {
      prefix: "",
      policies: [],
      auth: {
        scope: "plugin::users-permissions.user.updateMe" // 新增权限标识
      }
    },
  });

  // 注册新权限到插件权限列表
  plugin.permissions["content-api"].routes.push({
    method: "PUT",
    path: "/user/me",
    policy: "",
    scope: "plugin::users-permissions.user.updateMe"
  });

  // 为权限添加后台显示名称(可选)
  if (!plugin.permissions["content-api"].controllers.user) {
    plugin.permissions["content-api"].controllers.user = {};
  }
  plugin.permissions["content-api"].controllers.user.updateMe = {
    enabled: true,
    policy: "",
    scope: "plugin::users-permissions.user.updateMe",
    displayName: "更新自己的用户信息",
    description: "允许用户修改自身用户名"
  };

  return plugin;
};

关键修改说明

  • 在路由的config.auth.scope中定义权限唯一标识,格式为plugin::插件名.控制器名.方法名
  • 将新权限添加到plugin.permissions["content-api"].routes数组,让Strapi识别该权限
  • 可选配置displayName和description,让后台面板显示更友好的权限名称和说明

修改完成后重启Strapi服务,就能在「已认证用户」的用户权限列表中找到对应的权限选项了。

内容的提问来源于stack exchange,提问作者FD3

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 12:35:00