documentation icon indicating copy to clipboard operation
documentation copied to clipboard

IsOwner Guide Update for V4 Fix for #652

Open nextrapi opened this issue 3 years ago • 13 comments

What does it do?

Updates the IsOwner guide for Strapi v4

Why is it needed?

The current guide is deprecated.

Important to note that I think this guide is useful and popular enough that it should be added to the sidebar but I haven't done that yet.

Related issue(s)/PR(s)

Fix for #652

nextrapi avatar Jan 25 '22 04:01 nextrapi

This pull request is being automatically deployed with Vercel (learn more).
To see the status of your deployment, click below or on the icon next to each commit.

🔍 Inspect: https://vercel.com/strapijs/documentation/DP1Apd2LsKUm4H3TnojFUJnV1vHV
✅ Preview: https://documentation-git-fork-nextrapi-dev-isowner-v4-strapijs.vercel.app

vercel[bot] avatar Jan 25 '22 04:01 vercel[bot]

CLA assistant check
All committers have signed the CLA.

strapi-cla avatar Jan 25 '22 04:01 strapi-cla

Hi @derrickmehaffy, thank you a lot for your feedback. I updated the code using policies and middlewares. This is a strapi project with the example code: https://github.com/nextrapi/Strapi_v4_IsOwner

If you can give me any feedback on the code or the way its written, I can do another update and rewording.

nextrapi avatar Jan 28 '22 12:01 nextrapi

Hi @derrickmehaffy, thank you a lot for your feedback. I updated the code using policies and middlewares. This is a strapi project with the example code: https://github.com/nextrapi/Strapi_v4_IsOwner

If you can give me any feedback on the code or the way its written, I can do another update and rewording.

Yes I'll try and provide some feedback hopefully later today if I get some time or on monday if my schedule fills up

derrickmehaffy avatar Jan 28 '22 17:01 derrickmehaffy

Hi @nextrapi i try your solution and it's works perfectly, thanks a lot. But i have a little problem, when i try to make post request from my app i have an error:

{
  "status": 403,
  "name": "TypeError",
  "message": "Cannot set property 'author' of undefined",
  "details": {}
}

But from postman it works fine. Maybe you can tell me what i'm doing wrong? My axios call:

      axios({
        method: "POST",
        url: "http://localhost:1337/api/articles",
        headers: {
          "content-type": "application/json",
          Authorization: `Bearer ${window.localStorage.getItem("jwt")} `,
        },
        title: "Test article from app",
      });

Spasio avatar Jan 29 '22 00:01 Spasio

Hi @nextrapi i try your solution and it's works perfectly, thanks a lot. But i have a little problem, when i try to make post request from my app i have an error:

{
  "status": 403,
  "name": "TypeError",
  "message": "Cannot set property 'author' of undefined",
  "details": {}
}

But from postman it works fine. Maybe you can tell me what i'm doing wrong? My axios call:

      axios({
        method: "POST",
        url: "http://localhost:1337/api/articles",
        headers: {
          "content-type": "application/json",
          Authorization: `Bearer ${window.localStorage.getItem("jwt")} `,
        },
        title: "Test article from app",
      });

Hi @Spasio, thank you but I think your axios config is wrong. Try this:

var axios = require('axios');
axios({
  method: 'post',
  url: 'http://localhost:1337/api/articles',
  headers: { 
    'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNjQzNDM1OTg2LCJleHAiOjE2NDYwMjc5ODZ9.byIvqOTfx-zNjN85v3OCirBAubaKt3YqOZ5mNI0y370', 
    'Content-Type': 'application/json'
  },
  data : JSON.stringify({"data":{"title":"Test"}})
})

I am however going to correct it so it returns the correct error!

nextrapi avatar Jan 29 '22 07:01 nextrapi

Hi @nextrapi i try your solution and it's works perfectly, thanks a lot. But i have a little problem, when i try to make post request from my app i have an error:

{
  "status": 403,
  "name": "TypeError",
  "message": "Cannot set property 'author' of undefined",
  "details": {}
}

But from postman it works fine. Maybe you can tell me what i'm doing wrong? My axios call:

      axios({
        method: "POST",
        url: "http://localhost:1337/api/articles",
        headers: {
          "content-type": "application/json",
          Authorization: `Bearer ${window.localStorage.getItem("jwt")} `,
        },
        title: "Test article from app",
      });

Hi @Spasio, thank you but I think your axios config is wrong. Try this:

var axios = require('axios');
axios({
  method: 'post',
  url: 'http://localhost:1337/api/articles',
  headers: { 
    'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNjQzNDM1OTg2LCJleHAiOjE2NDYwMjc5ODZ9.byIvqOTfx-zNjN85v3OCirBAubaKt3YqOZ5mNI0y370', 
    'Content-Type': 'application/json'
  },
  data : JSON.stringify({"data":{"title":"Test"}})
})

I am however going to correct it so it returns the correct error!

Thanks for fast reply, your axios config solved my problem. Now everything working great!

Spasio avatar Jan 29 '22 18:01 Spasio

This pull request has been mentioned on Strapi Community Forum. There might be relevant details there:

https://forum.strapi.io/t/isowner-policy-in-strapi-4-0/14824/5

strapi-bot avatar Jan 29 '22 18:01 strapi-bot

} else {
      ctx.request.query.filters = { ...ctx.request.query.filters, [field]: userId };
      return true;
    }

You can't do this, setting stuff in the policy ctx won't travel down the chain. You can't set something in a policy only return true/false.

I think this policy could be simplified quite a bit.


I also don't understand the purpose of the middleware

derrickmehaffy avatar Jan 31 '22 21:01 derrickmehaffy

Hey everyone, at the moment my code in isOwner.js policy looks like this:

module.exports = async (ctx, next) => {
  const { id } = ctx.params;
  const userID = ctx.state.user.id;
  if (id) {
    // content type is hardcoded in this example
    const [entity] = await strapi.entityService.findMany('api::article.article', {
      filters: { id, author: userID },
    });
    if (entity) {
      return true;
    }
  }
  return false
}

As far as I have understood, this works for update, findOne and delete controllers (everything that works on one article). However, what would be the approach if I would want to filter the find controller in a policy? Or am I just able to filter in the controller, e.g. article.js:

module.exports = createCoreController('api::article.article', ({ strapi }) => ({
    async find(ctx) {
        const { data, meta} = await super.find(ctx);
        const { user } = ctx.state;
        let articles = onlyAuthorArticles(data, user);
        return {articles, meta}; 
    }
}));

function onlyAuthorArticles(articles, user) {
    let filteredArticles = articles.filter(article => article.attributes.author.data.id == user.id);
    return filteredArticles;
}

Filtering the ctx object in the policy file is not possible as @derrickmehaffy mentioned.

My approach works I am just not sure if it is the most sensible approach (I doubt that :D)

alpakaxaxa avatar Feb 02 '22 14:02 alpakaxaxa

@Convly and/or @petersg83 I'd like to have your review on the suggested changes, from a technical point of view, before I can have my technical writing review ready :-)

pwizla avatar Feb 18 '22 13:02 pwizla

@nextrapi I am very grateful for this documentation PR. I've been looking for a solution for a long time and this one fits like a glove, thanks 🚀 ❤️

leandrosena avatar Mar 11 '22 06:03 leandrosena

Hello @derrickmehaffy , @petersg83 and @Convly . I'm following up on this PR to have your technical feedback and see how we can go forward with it 😎

pwizla avatar May 04 '22 09:05 pwizla

Hello everyone! I'm closing this PR as the recommended way to add an "is-owner policy" equivalent in Strapi v4 is now documented: https://docs.strapi.io/dev-docs/backend-customization/middlewares#restricting-content-access-with-an-is-owner-policy

pwizla avatar Aug 22 '23 15:08 pwizla