Access Control
Limit the access of content.
Overview
Thanks to the flexible design, it is simple to implement access control with Fumadocs.
Loader API
If you are using loader() API, you can create the loaders on-demand, and filter files from content source to restrict accessible content.
For example, this setup only shows the pages with frontmatter permission: public.
import { getCollection } from 'astro:content';
import { loader, update } from 'fumadocs-core/source';
import { toFumadocsSource } from '@fumadocs/astro/source';
const filteredSource = update(
toFumadocsSource(await getCollection('docs'), await getCollection('meta')),
)
.files((files) =>
files.filter((file) => {
// keep meta files (e.g. `meta.json`)
if (file.type === 'meta') return true;
return file.data.permission === 'public';
}),
)
.build();
export const source = loader(filteredSource, {
baseUrl: '/docs',
});For more complicated setups, you can turn source into a factory function.
import { getCollection } from 'astro:content';
import { loader, update } from 'fumadocs-core/source';
import { toFumadocsSource } from '@fumadocs/astro/source';
const pages = await getCollection('docs');
const metas = await getCollection('meta');
// uncached, it's better to cache it in-memory for real use case.
export function createSource(permission: 'public' | 'admin') {
const filteredSource = update(toFumadocsSource(pages, metas))
.files((files) =>
files.filter((file) => {
if (file.type === 'meta') return true;
return file.data.permission === permission;
}),
)
.build();
return loader(filteredSource, {
baseUrl: '/docs',
});
}Advantages
What is special with this approach is that the access is limited at input level, rather than at rendering phase or build-time.
This guarantees the protected content is filtered entirely, and without compromise on flexibility.
Custom Implementation
Without the Loader API, implement access control in Astro, such as in routes or middleware.
For example, to limit access to certain pages:
---
import { source } from '@/lib/source';
// render per request, needs an adapter
export const prerender = false;
const slugs = Astro.params.slug?.split('/').filter((v) => v.length > 0) ?? [];
const user = await getUser(Astro.request);
const page = source.getPage(slugs);
if (!page || page.data.permission !== user.permission) {
return Astro.rewrite('/404');
}
---
<!-- render page... -->Note that it is up to you to manage the page tree (sidebar items), search, Markdown routes and other details.
This approach gives the most flexibility, but Fumadocs does not handle the access control. The setup takes more work, so consult the Astro docs when implementing it.
How is this guide?
Last updated on
