I have order app created on strapi, how can I secure data from other users, but user who create order can view him.
I use relation one-to-many from user to many orders, when ?populate=orders
requests other authorized users can view them, and when I turn off find
action this field removing from /users/me?populate=orders
.
How can I set visibility for order by user who made it?
you would need a middleware for this, the more general approach is to use policy to make users not able to fetch other user data, like here: Why all users in Strapi have access to update all users profile?
So let's mod code a bit to fit your case, the steps we are going to do are following:
user-permissions
routes.orders
from request if user aren't the one that is registered.The result is if we do /api/users?populate=orders
or /api/users/:id?populate=orders
we would not receive orders.
So:
strapi generate
? Strapi Generators middleware
? Middleware name orders
? Where do you want to add this middleware? Add middleware to root of project
So by default middleware would log in console:
'In orders middleware.'
We need to apply it to find
, findOne
, update
, delete
routes of user-permissions plugin:
src/extensions/user-permissions/strapi-server.js
module.exports = (plugin) => {
for (let i = 0; i < plugin.routes["content-api"].routes.length; i++) {
const route = plugin.routes["content-api"].routes[i];
// checks if this one of the routes we target
if (
route.handler === "user.findOne" ||
route.handler === "user.find" ||
route.handler === "user.update" ||
route.handler === "user.destroy"
) {
// if it's append middleware to route
plugin.routes["content-api"].routes[i] = {
...route,
config: {
...route.config,
middlewares: route.config.middlewares
? [...route.config.middlewares, "global::orders"]
: ["global::orders"],
},
};
}
}
return plugin;
};
yarn build
yarn develop
If you did the step correct you should see:
[2023-02-14 14:59:51.472] http: GET /api/users (30 ms) 200
[2023-02-14 15:00:01.852] info: In orders middleware.
every time you hit /api/users
Next step we going to tweak middleware, so middleware has two stages, first stage is before await next()
it's stage that executed before controller, the second stage is after await next()
is stage executed after controller.
We are going to modify the second stage and if we find attribute orders
we are going to remove it from response:
src/middlewares/orders.js
'use strict';
/**
* `orders` middleware
*/
module.exports = (config, { strapi }) => {
return async (ctx, next) => {
// before controller
await next();
// after controller
// we need to check if the reponse is correct,
// otherwise we will have error message in the data
if (ctx.response.status === 200) {
// get the authenticated user, if no user - undefined
const { user } = ctx.state;
// get data from response
let data = ctx.response.body;
// check if data is array
if (Array.isArray(data)) {
// run sanitize function for each element
data = data.map(item => sanitizeItem(item, user))
} else {
// else run for single item
data = sanitizeItem(data, user);
}
// apply result to response
ctx.response.body = data;
}
};
};
// sanitizer function
const sanitizeItem = (item, user) => {
// check if user is not undefined
if (user) {
// check if user id is same as the item.id (user from request)
if (user.id === item.id) {
// if it's same return full object
return item;
}
}
// else extract orders from object
let { orders, ...rest } = item;
return rest;
}
And whoala:
[
{
"id": 1,
"username": "user1",
"email": "[email protected]",
"provider": "local",
"confirmed": true,
"blocked": false,
"createdAt": "2023-02-14T11:39:43.246Z",
"updatedAt": "2023-02-14T11:39:43.246Z",
"orders": [
{
"id": 1,
"title": "Order 1",
"createdAt": "2023-02-14T11:39:01.990Z",
"updatedAt": "2023-02-14T11:39:01.990Z"
},
{
"id": 2,
"title": "Order 2",
"createdAt": "2023-02-14T11:39:09.182Z",
"updatedAt": "2023-02-14T11:39:09.182Z"
}
]
},
{
"id": 2,
"username": "user2",
"email": "[email protected]",
"provider": "local",
"confirmed": true,
"blocked": false,
"createdAt": "2023-02-14T11:40:04.793Z",
"updatedAt": "2023-02-14T11:40:04.793Z"
}
]
I'm authenticated as user1