Applying isOwner Policy to user-permissions Plugin

System Information
  • Strapi Version:
    3.0.5
  • Operating System:
    Ubuntu 20.04
  • Database:
    PG
  • Node Version:
    12.18.2
  • NPM Version:
    6.14.5
  • Yarn Version:

Hi,
I’m trying to implement JIm’s suggestion described here [1] in order to restrict users to update only their data/user profile (by implementing an isOwner policy).
So, I’ve created isOwner.js placed it in /config/policies:
module.exports = async (ctx, next) => {
if (ctx.state.user.id === ctx.params.id) {
// Go to next policy or will reach the controller’s action.
return await next();
}

ctx.unauthorized(You're not allowed to perform this action!);
};

Also created a routes.json file under /extensions/user-permissions/config with this route at this point:
{
“routes”: [
{
“method”: “PUT”,
“path”: “/users/:id”,
“handler”: “User.update”,
“config”: {
“policies”: [
“global::isOwner”
]
}
}
]
}

My intention here was to override the plugin’s built-in route so it will go through the new policy, but it seems not to be working as the old/other definition is used.
What am I doing wrong?

Best regards,
Yossi

[1] strapi - How to change password after logging in? - Stack Overflow

In this case, you’ve actually got two routes. The first one is yours from extensions and the second one is strapi’s default route. Under the same hander User.update. All your custom routes from extensions are merged with user-permission routes.

image

Also, all the routes created in the Plugins, are prefixed with the plugin’s name by default.

So if you are calling PUT /users/1 to update the user then it uses the user-permissions’s route with default policies and not your custom route with isOwner policy. In the current example, your route is accessible under PUT /users-permissions/users/1. Also, in this case if you grant permissions for user to Update, the user will have access to update it’s own profile under /user-permissions/users/:id and ANY other user under /users/:id.

You can’t completely overwrite the plugin’s routes. Since these are merged. As if you could completely overwrite the default routes then you would break its functionality.

BTW The updateMe functionality is in WIP.

I would recommend adding a new route that is not identical to user-permissions routes, that one should update the user by getting the ID from token.

1 Like

Thanks, I’ve followed your suggestion and created a new route for this purpose, also revoked access to other /user routes to avoid ability that a user updates (or deletes) a different user.

A several things to bear in mind:

  1. You should verify yourself that the updated email and/or user is not taken (this is done when using /users/:id)
  2. You should hash the new password (if provided) before saving it by:

    await strapi.plugins[“users-permissions”].services.user.hashPassword({ password })
  3. Also make sure to nullify resetPasswordToken field once changing the password.

Thanks again for your assistance,
Yossi

You can use strapi’s default controllers inside your custom controller:

module.exports = {
  async someCustomUpdateController(ctx) {
    return strapi.plugins["users-permissions"].controllers.user.update(ctx);
  }
}

That someCustomUpdateController is used as a handler on a new custom route with a custom policy isOwner, after passing the isOwner policy it uses the strapi’s core controller. Same approach if for other functions.

You can output the: strapi.plugins["users-permissions"].controllers in console log to see what other functions are inside.

That’s more like it, very elegant, just implemented and it indeed did the trick.
Thanks!!!

1 Like

Hello Yossi,

it seems that you found a solution I’m looking for. I also want that a user can change the password from a vue app frontend. And also found the Stackoverflow link you have provided.

Would you please be so kind to give some details with your implemented policy. Where did you put this policy to - which which directory?. How to activate it? In the strapi backend?!

I’m new within the strapi policy subject and could need a little “tutorial like” help on this subject.

Best regards and much appreciated
Frank