xenial-black
xenial-blackβ€’12mo ago

Access parent or parentName or dataProviderName inside of the accessControlProvider Property

We are currently working on the integration of ACLs into our project, but we're stumbling across the passed in params object. First of all for clarification some code:
accessControlProvider={{
can: async ({ action, params, resource }) => {
const enforcer = await newEnforcer(
newModel(authStore.model),
new StringAdapter(authStore.policies),
);
if (resource === 'dashboard') {
return Promise.resolve({ can: true });
}

const parent = params?.resource?.meta?.parent;

return {
can: await enforcer.enforce(parent, resource, action),
};
},
}}
accessControlProvider={{
can: async ({ action, params, resource }) => {
const enforcer = await newEnforcer(
newModel(authStore.model),
new StringAdapter(authStore.policies),
);
if (resource === 'dashboard') {
return Promise.resolve({ can: true });
}

const parent = params?.resource?.meta?.parent;

return {
can: await enforcer.enforce(parent, resource, action),
};
},
}}
The code does what it should, but only on the Landingpage, where the params.resource will always hold the actual resource it is asking for. As soon as we move to the List-Page, the checks are run again, but this time for every resource item (i.e. specific post) inside of the list. This time the params.resource is {id: 1} where it holds the resource items ID. This means we can no longer access the params?.resource?.meta?.parent. I thought about using useResource, but that seems a bit like a hacky workaround to me. Any idea on how to solve this? πŸ˜…
31 Replies
kapa.ai
kapa.aiβ€’12mo ago
Hi @bastianwegge. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Hmm, I don't know enough to give you a confident answer yet. However, you can refer to the refine documentation on Access Control Provider (https://refine.dev/docs/api-reference/core/providers/accessControl-provider) for more information on how to work with the params object and access control in refine. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.aiβ€’12mo ago
<@317433576721219584> kapa.ai is still learning and improving, please let us how it did by reacting below
xenial-black
xenial-blackβ€’12mo ago
@kapa.ai can I get the active Resource inside my App.tsx file?
kapa.ai
kapa.aiβ€’12mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- Yes, you can get the active resource inside your App.tsx file using the useResource hook. Here's an example of how to use it:
import { useResource } from "@refinedev/core";

const App: React.FC = () => {
const { resource } = useResource();

// Your logic with the active resource

return (
<Refine
// Your refine configuration
>
{/* Your app */}
</Refine>
);
};

export default App;
import { useResource } from "@refinedev/core";

const App: React.FC = () => {
const { resource } = useResource();

// Your logic with the active resource

return (
<Refine
// Your refine configuration
>
{/* Your app */}
</Refine>
);
};

export default App;
You can find more information about the useResource hook in the refine documentation (https://refine.dev/docs/api-reference/core/hooks/resource/useResource/). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.aiβ€’12mo ago
<@317433576721219584> kapa.ai is still learning and improving, please let us how it did by reacting below
xenial-black
xenial-blackβ€’12mo ago
@kapa.ai that does not work, as it's probably out of Context of Refine
kapa.ai
kapa.aiβ€’12mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- Apologies for the confusion. You're right, using the useResource hook directly in App.tsx might not work as it's outside the context of Refine. Instead, you can create a wrapper component inside the <Refine> component and use the useResource hook there. Here's an example:
import { Refine } from "@refinedev/core";
import { useResource } from "@refinedev/core";

const WrapperComponent: React.FC = () => {
const { resource } = useResource();

// Your logic with the active resource

return (
// Your app components
);
};

const App: React.FC = () => {
return (
<Refine
// Your refine configuration
>
<WrapperComponent />
</Refine>
);
};

export default App;
import { Refine } from "@refinedev/core";
import { useResource } from "@refinedev/core";

const WrapperComponent: React.FC = () => {
const { resource } = useResource();

// Your logic with the active resource

return (
// Your app components
);
};

const App: React.FC = () => {
return (
<Refine
// Your refine configuration
>
<WrapperComponent />
</Refine>
);
};

export default App;
This way, you can access the active resource within the context of Refine. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.aiβ€’12mo ago
<@317433576721219584> kapa.ai is still learning and improving, please let us how it did by reacting below
xenial-black
xenial-blackβ€’12mo ago
@kapa.ai nice work, but how would you then go ahead and pass the results of the useResource hook back to the parent Refine component for Authorization? πŸ˜„
kapa.ai
kapa.aiβ€’12mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- To pass the results of the useResource hook back to the parent Refine component for Authorization, you can create a custom Access Control Provider and pass it to the accessControlProvider prop of the <Refine> component. Here's an example: 1. Create a custom Access Control Provider component:
import {{ createContext, useContext }} from "react";
import {{ useResource }} from "@refinedev/core";

const ActiveResourceContext = createContext(null);

const CustomAccessControlProvider: React.FC = ({ children }) => {{
const {{ resource }} = useResource();

// Your logic with the active resource

return (
<ActiveResourceContext.Provider value={{ resource }}>
{children}
</ActiveResourceContext.Provider>
);
}};

export const useActiveResource = () => {{
return useContext(ActiveResourceContext);
}};
import {{ createContext, useContext }} from "react";
import {{ useResource }} from "@refinedev/core";

const ActiveResourceContext = createContext(null);

const CustomAccessControlProvider: React.FC = ({ children }) => {{
const {{ resource }} = useResource();

// Your logic with the active resource

return (
<ActiveResourceContext.Provider value={{ resource }}>
{children}
</ActiveResourceContext.Provider>
);
}};

export const useActiveResource = () => {{
return useContext(ActiveResourceContext);
}};
2. Use the custom Access Control Provider component inside the <Refine> component:
import {{ Refine }} from "@refinedev/core";
import CustomAccessControlProvider, {{ useActiveResource }} from "./CustomAccessControlProvider";

const App: React.FC = () => {{
return (
<Refine
accessControlProvider={{
can: async ({{ action, params, resource }}) => {{
const activeResource = useActiveResource();

// Your logic with the active resource for authorization

return {{ can: true }};
}},
}}
// Your refine configuration
>
<CustomAccessControlProvider>
// Your app components
</CustomAccessControlProvider>
</Refine>
);
}};

export default App;
import {{ Refine }} from "@refinedev/core";
import CustomAccessControlProvider, {{ useActiveResource }} from "./CustomAccessControlProvider";

const App: React.FC = () => {{
return (
<Refine
accessControlProvider={{
can: async ({{ action, params, resource }}) => {{
const activeResource = useActiveResource();

// Your logic with the active resource for authorization

return {{ can: true }};
}},
}}
// Your refine configuration
>
<CustomAccessControlProvider>
// Your app components
</CustomAccessControlProvider>
</Refine>
);
}};

export default App;
This way, you can access the active resource within the context of Refine and use it for authorization in your custom Access Control Provider. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.aiβ€’12mo ago
<@317433576721219584> kapa.ai is still learning and improving, please let us how it did by reacting below
xenial-black
xenial-blackβ€’12mo ago
@kapa.ai you are printing out double quotes instead of single quotes.
kapa.ai
kapa.aiβ€’12mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- Apologies for the formatting issue in my previous responses. Here's the corrected example: 1. Create a custom Access Control Provider component:
import { createContext, useContext } from "react";
import { useResource } from "@refinedev/core";

const ActiveResourceContext = createContext(null);

const CustomAccessControlProvider: React.FC = ({ children }) => {
const { resource } = useResource();

// Your logic with the active resource

return (
<ActiveResourceContext.Provider value={resource}>
{children}
</ActiveResourceContext.Provider>
);
};

export const useActiveResource = () => {
return useContext(ActiveResourceContext);
};
import { createContext, useContext } from "react";
import { useResource } from "@refinedev/core";

const ActiveResourceContext = createContext(null);

const CustomAccessControlProvider: React.FC = ({ children }) => {
const { resource } = useResource();

// Your logic with the active resource

return (
<ActiveResourceContext.Provider value={resource}>
{children}
</ActiveResourceContext.Provider>
);
};

export const useActiveResource = () => {
return useContext(ActiveResourceContext);
};
2. Use the custom Access Control Provider component inside the <Refine> component:
import { Refine } from "@refinedev/core";
import CustomAccessControlProvider, { useActiveResource } from "./CustomAccessControlProvider";

const App: React.FC = () => {
return (
<Refine
accessControlProvider={{
can: async ({ action, params, resource }) => {
const activeResource = useActiveResource();

// Your logic with the active resource for authorization

return { can: true };
},
}}
// Your refine configuration
>
<CustomAccessControlProvider>
// Your app components
</CustomAccessControlProvider>
</Refine>
);
};

export default App;
import { Refine } from "@refinedev/core";
import CustomAccessControlProvider, { useActiveResource } from "./CustomAccessControlProvider";

const App: React.FC = () => {
return (
<Refine
accessControlProvider={{
can: async ({ action, params, resource }) => {
const activeResource = useActiveResource();

// Your logic with the active resource for authorization

return { can: true };
},
}}
// Your refine configuration
>
<CustomAccessControlProvider>
// Your app components
</CustomAccessControlProvider>
</Refine>
);
};

export default App;
This way, you can access the active resource within the context of Refine and use it for authorization in your custom Access Control Provider. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.aiβ€’12mo ago
<@317433576721219584> kapa.ai is still learning and improving, please let us how it did by reacting below
xenial-black
xenial-blackβ€’12mo ago
That does unfortunately not work as you cannot use hooks inside of Properties of Components πŸ˜„ @kapa.ai can you remove your answers?
kapa.ai
kapa.aiβ€’12mo ago
Let me check the knowledge base for you. One moment! :books: @bastianwegge That's a great question, but unfortunately I am only capable of responding to a maximum of three questions per thread. Don't hesitate to create a new thread for any further questions you have though. I'm here to help!
xenial-black
xenial-blackβ€’12mo ago
Maybe someone from @core can take a look at the initial question. I'm just trying to get the parent or parent.name or dataProviderName from my resource inside of the accessControlProvider.
metropolitan-bronze
metropolitan-bronzeβ€’12mo ago
Hey @bastianwegge, interesting issue. Sorry for that! We should be sending the active resource in the params but you say that it's not available in the params. The access controll will run for every item in the list if you have any buttons attached to them. Do i understand the issue correctly?
xenial-black
xenial-blackβ€’12mo ago
Yeah I think you got the gist of it. Params is just { id: 1 }
metropolitan-bronze
metropolitan-bronzeβ€’12mo ago
I will check this now, can you provide a bit more info about the router structure and page? Do buttons are the ones checking the access control?
xenial-black
xenial-blackβ€’12mo ago
@aliemirs sorry it's quite late here so I couldn't respond that quickly. I will try to reproduce the example we have here and ping you again.
metropolitan-bronze
metropolitan-bronzeβ€’12mo ago
Thinking this might be related to your previous issues with the identifier
xenial-black
xenial-blackβ€’12mo ago
I'm just trying to recreate it using the refine casbin example on codesandbox.
xenial-black
xenial-blackβ€’12mo ago
Can you open this sandbox? -> https://codesandbox.io/s/bitter-bird-k47lgz?file=/src/App.tsx Open it, wait for codesandbox to install and open your own console (not the codesandbox one). Open the navigation and click on "posts", this is where the console log spits out the following:
No description
xenial-black
xenial-blackβ€’12mo ago
This page here (https://refine.dev/docs/api-reference/core/providers/accessControl-provider/#hooks-and-components) shows a section where it says: "You can also access the resource object directly." and then a code-example which includes:
const anyUsefulMeta = params?.resource?.meta?.yourUsefulMeta;
const anyUsefulMeta = params?.resource?.meta?.yourUsefulMeta;
But the params.resource is often just a ID or even sometimes undefined but not the original resource.
metropolitan-bronze
metropolitan-bronzeβ€’12mo ago
Thank you for the explanation, checking it in short time an get back to you πŸ™ Btw, we’ve had some progress in the identifier issue and will release it tomorrow. I will also check this issue with the current changes to see if this continues
xenial-black
xenial-blackβ€’12mo ago
Very cool news, thank you
metropolitan-bronze
metropolitan-bronzeβ€’12mo ago
Hey @bastianwegge, sorry for the late update. The identifier related changes are released to the latest channel with @refinedev/core@4.24.0, you will also need to update the other packages to latest for a seamless transition of course. And with the 4.25.0 which is released to next channel for now, we have fixed the issues with the access control and the resource Hope this will fix your issues, please let us know when you can verify its fixed πŸ™πŸ™
xenial-black
xenial-blackβ€’12mo ago
This is the best news this week! Weβ€˜re currently enjoying the sun, but I will definitely check out the release as soon as I get home. Thanks for the updates! Thanks for keeping me in the loop! You guys are awesome! @aliemirs everything works as expected, I immediately switched to 4.25.0 πŸ‘ πŸš€ Thank you very much!
fair-rose
fair-roseβ€’12mo ago
Hey @bastianwegge that's great to hear! Feel free to any other issue you've encountered, we are more than happy to help! Kbar refactor is on our backlog, but we have a bank holiday this week, so we'll deliver it in the next 2+ weeks.
xenial-black
xenial-blackβ€’12mo ago
Yeah no stress on kbar, as we have the solution at hand, you can go easy on that one. Again: Thank you so much for the great communication in Discord! ❀️