# Fumadocs (Framework Mode, Astro): 存取控制
URL: /zh-TW/docs/astro/guides/access-control
Source: https://raw.githubusercontent.com/fuma-nama/fumadocs/refs/heads/main/apps/docs/content/docs/(framework)/[framework]/guides/access-control.zh-TW.mdx

限制內容的存取權限。

## 概覽 [#overview]

由於 Fumadocs 的設計相當有彈性，實作存取控制十分簡單。

## 載入器 API [#loader-api]

如果您使用 [`loader()`](/docs/headless/source-api) API，可以視需要建立載入器，並篩選內容來源中的檔案，藉此限制可存取的內容。

例如，以下設定只會顯示 frontmatter 含有 `permission: public` 的頁面。

```ts title="src/lib/source.ts"
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) => {
      // 保留 meta 檔案（例如 `meta.json`）
      if (file.type === 'meta') return true;

      return file.data.permission === 'public';
    }),
  )
  .build();

export const source = loader(filteredSource, {
  baseUrl: '/docs',
});
```

若設定較為複雜，您可以將 `source` 改寫為工廠函式。

```ts title="src/lib/source.ts"
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');

// 未快取，實際使用時建議快取在記憶體中。
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',
  });
}
```

接著為每位使用者建立來源：

```ts
// [!code --]
import { source } from '@/lib/source';
// [!code ++:4]
import { createSource } from '@/lib/source';

const user = await getUser();
const source = createSource(user.permission);

const page = source.getPage(params.slugs);
```

### 優點 [#advantages]

這種做法的特別之處在於，**存取限制是在輸入層級就套用**，而不是在算繪階段或建置時才進行。

如此可確保受保護的內容完全被過濾掉，且絲毫不犧牲彈性。

## 自訂實作 [#custom-implementation]

若不使用載入器 API，請直接在 Astro 中實作存取控制，例如在路由或中介軟體中處理。

例如，若要限制特定頁面的存取權限：

```astro title="src/pages/docs/[...slug].astro"
---
import { source } from '@/lib/source';

// 每次請求時算繪，需要轉接器
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');
}
---

<!-- 算繪頁面... -->
```

請注意，頁面樹 (側邊欄項目) 、搜尋、Markdown 路由及其他細節都需要由您自行處理。

這種做法彈性最高，但 Fumadocs 不會替您處理存取控制。設定較為費工，實作時請參閱 Astro 的文件。