afraid-scarlet
afraid-scarletβ€’15mo 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β€’15mo 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β€’15mo ago
<@317433576721219584> kapa.ai is still learning and improving, please let us how it did by reacting below
afraid-scarlet
afraid-scarletβ€’15mo ago
@kapa.ai can I get the active Resource inside my App.tsx file?
kapa.ai
kapa.aiβ€’15mo 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β€’15mo ago
<@317433576721219584> kapa.ai is still learning and improving, please let us how it did by reacting below
afraid-scarlet
afraid-scarletβ€’15mo ago
@kapa.ai that does not work, as it's probably out of Context of Refine
kapa.ai
kapa.aiβ€’15mo 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β€’15mo ago
<@317433576721219584> kapa.ai is still learning and improving, please let us how it did by reacting below
afraid-scarlet
afraid-scarletβ€’15mo 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β€’15mo 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β€’15mo ago
<@317433576721219584> kapa.ai is still learning and improving, please let us how it did by reacting below
afraid-scarlet
afraid-scarletβ€’15mo ago
@kapa.ai you are printing out double quotes instead of single quotes.
kapa.ai
kapa.aiβ€’15mo 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β€’15mo ago
<@317433576721219584> kapa.ai is still learning and improving, please let us how it did by reacting below
afraid-scarlet
afraid-scarletβ€’15mo ago
That does unfortunately not work as you cannot use hooks inside of Properties of Components πŸ˜„ @kapa.ai can you remove your answers?