Role based access to articles

Hi everybody,

struggling a bit with how to set up my Strapi right now. I have an endpoint /posts and I need to return these posts depending on the role of the requesting user.

Here is my problem:

  • I have an app, that displays articles for the customers of a company (B2B). Since it’s sensitive and relevant content for the business I’m building the app for, no articles should be returned to guest users.
  • So authenticated users can see content already. That works fine. However, there is another role - customers with a higher clearance - that should be able to see all articles, so some of the “normal members” shouldn’t be able to see this content.
  • I need to be absolutely sure, that a guest can’t see any content, and that a “normal member” can see none of the higher-clearance content

How would you go about implementing this? My idea was to implement a relation to the role-field from the users-permissions-plugin on my post data type. But how could I make sure strapi only returns content cleared for the requesting user?

Some input would be much appreciated!

Cheers from Bavaria,
Max

One possible solution could be to implement a relation between the articles and the users and a field (string or enum) to define the roles that have access to the article; then you would define a middleware to limit the access on the articles basing on the correspondance between the user role and the roles allowed to access the article

@DMehaffy can you think about alternative solutions?

Hi @macco

thanks for your ideas! In the meantime I came up with the following (and I brought a follow-up question :slight_smile: )

  • In the GUI, I added a boolean to the post collection
  • I called it isPremium and its pretty helpful as the editors will be able to set this during post writing
  • Also in the GUI I created a new role “Premium” that user’s need to be given manually (for now actually manual, later I’ll create some business logic for that in my frontend)
  • Then I created a dedicated custom controller to handle the permissions checking
  • The controller fetches the JWT from the requests, resolves it and checks if the user belongs to the right group/role

By this I was able to realise a role-based access to my articles!

However one Problem remains:
When I call {API}/post-list?populate=* from my frontend, in the console of my backend the following get’s logged: GET /api/post-list?populate=%2A and the population is not done.

I’ll drop my code here, maybe you can spot where I went wrong :slight_smile: because I am completely cluesless about this one^^

Cheers,
Max

Router:

module.exports = {
    routes: [
        {
            method: 'GET',
            path: '/post-list',
            handler: 'post.filteredList',
            config: {
                auth: false,
            }
        }
    ]
}

Controller:


'use strict';

/**
 * post controller
*/

const { createCoreController } = require('@strapi/strapi').factories;
const jwt_decode = require('jwt-decode');

module.exports = createCoreController('api::post.post', {
    
    
    async filteredList(ctx) {
        
        ctx.query = { ...ctx.query}
        let { data, meta } = await super.find(ctx);

        const notPremiumData = data.filter((item) => {
            return item.attributes.isPremium !== true;
        });

        const jwt = ctx.request.header.authorization;
        const premiumUser = isUserPremium(jwt);

        if(premiumUser !== true) {
            data = notPremiumData;
        }

        return { data, meta };
    },
    
});

// returns true if user is premium and false if not
const isUserPremium = async (jwt) => {
    const userId = jwt_decode(jwt).id;

    const user = await strapi.entityService.findOne('plugin::users-permissions.user', userId, {populate: { role: true}});

    const userIsPremium = user.role.name === 'Premium';

    return userIsPremium;
};

Per my understanding, the Rest API parameters won’t work because you are creating a custom handler (correct me if that is not the case). The approach I took to doing something similar to what you are trying is the following:

I wrote a middleware for the find operation which adds filter params based on the requesting user’s access. This way, all the standard Strapi Rest API params should work.