Skip to content

Commit c9aff15

Browse files
authored
Merge pull request #6 from weizwz/dev
Dev
2 parents a78e5a8 + 1fcb56d commit c9aff15

File tree

15 files changed

+2224
-23
lines changed

15 files changed

+2224
-23
lines changed

.env.example

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,11 @@
44

55
# 生产环境
66
NEXT_PUBLIC_SITE_URL=https://nav.weizwz.com
7+
8+
# Iconify API URL(用于图标搜索和获取)
9+
# 默认值: https://api.iconify.design
10+
NEXT_PUBLIC_API_ICONIFY_URL=https://api.iconify.design
11+
12+
# Favicon API URL(用于获取网站图标)
13+
# 默认值: https://favicon.im
14+
NEXT_PUBLIC_FAVICON_API_URL=https://favicon.im

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ yarn-error.log*
2727

2828
# local env files
2929
.env*.local
30+
.env.production
3031

3132
# vercel
3233
.vercel
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
# Iconify 功能的 CSP 配置说明
2+
3+
## 概述
4+
5+
为了使 Iconify 图标选择功能正常工作,需要在 Content Security Policy (CSP) 中允许从 `api.iconify.design` 加载资源。
6+
7+
## 所需的 CSP 指令
8+
9+
### 1. connect-src
10+
11+
允许 JavaScript 代码连接到 Iconify API:
12+
13+
```
14+
connect-src 'self' https://api.iconify.design;
15+
```
16+
17+
### 2. img-src
18+
19+
允许加载 Iconify 图标图片:
20+
21+
```
22+
img-src 'self' data: https://api.iconify.design https://favicon.im;
23+
```
24+
25+
## 完整的 CSP 配置示例
26+
27+
### 方式 1: 在 Next.js 中间件中配置
28+
29+
创建或修改 `middleware.ts` 文件:
30+
31+
```typescript
32+
import { NextResponse } from 'next/server';
33+
import type { NextRequest } from 'next/server';
34+
35+
export function middleware(request: NextRequest) {
36+
const response = NextResponse.next();
37+
38+
// 设置 CSP 头
39+
response.headers.set(
40+
'Content-Security-Policy',
41+
[
42+
"default-src 'self'",
43+
"script-src 'self' 'unsafe-inline' 'unsafe-eval'",
44+
"style-src 'self' 'unsafe-inline'",
45+
"img-src 'self' data: https://api.iconify.design https://favicon.im",
46+
"connect-src 'self' https://api.iconify.design",
47+
"font-src 'self' data:",
48+
].join('; ')
49+
);
50+
51+
return response;
52+
}
53+
54+
export const config = {
55+
matcher: [
56+
'/((?!api|_next/static|_next/image|favicon.ico).*)',
57+
],
58+
};
59+
```
60+
61+
### 方式 2: 在 next.config.ts 中配置
62+
63+
```typescript
64+
const nextConfig: NextConfig = {
65+
async headers() {
66+
return [
67+
{
68+
source: '/:path*',
69+
headers: [
70+
{
71+
key: 'Content-Security-Policy',
72+
value: [
73+
"default-src 'self'",
74+
"script-src 'self' 'unsafe-inline' 'unsafe-eval'",
75+
"style-src 'self' 'unsafe-inline'",
76+
"img-src 'self' data: https://api.iconify.design https://favicon.im",
77+
"connect-src 'self' https://api.iconify.design",
78+
"font-src 'self' data:",
79+
].join('; '),
80+
},
81+
],
82+
},
83+
];
84+
},
85+
// ... 其他配置
86+
};
87+
```
88+
89+
### 方式 3: 在 HTML meta 标签中配置
90+
91+
`app/layout.tsx` 中添加:
92+
93+
```tsx
94+
export default function RootLayout({
95+
children,
96+
}: {
97+
children: React.ReactNode;
98+
}) {
99+
return (
100+
<html lang="zh-CN">
101+
<head>
102+
<meta
103+
httpEquiv="Content-Security-Policy"
104+
content="default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://api.iconify.design https://favicon.im; connect-src 'self' https://api.iconify.design; font-src 'self' data:;"
105+
/>
106+
</head>
107+
<body>{children}</body>
108+
</html>
109+
);
110+
}
111+
```
112+
113+
## 静态导出项目的特殊说明
114+
115+
由于本项目使用 `output: 'export'` 进行静态导出,CSP 配置需要在部署时由 Web 服务器(如 Nginx、Apache)或 CDN(如 Cloudflare、Vercel)设置。
116+
117+
### Nginx 配置示例
118+
119+
```nginx
120+
location / {
121+
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://api.iconify.design https://favicon.im; connect-src 'self' https://api.iconify.design; font-src 'self' data:;" always;
122+
}
123+
```
124+
125+
### Cloudflare Workers 配置示例
126+
127+
```javascript
128+
addEventListener('fetch', event => {
129+
event.respondWith(handleRequest(event.request))
130+
})
131+
132+
async function handleRequest(request) {
133+
const response = await fetch(request)
134+
const newResponse = new Response(response.body, response)
135+
136+
newResponse.headers.set(
137+
'Content-Security-Policy',
138+
"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://api.iconify.design https://favicon.im; connect-src 'self' https://api.iconify.design; font-src 'self' data:;"
139+
)
140+
141+
return newResponse
142+
}
143+
```
144+
145+
### Vercel 配置示例
146+
147+
`vercel.json` 中添加:
148+
149+
```json
150+
{
151+
"headers": [
152+
{
153+
"source": "/(.*)",
154+
"headers": [
155+
{
156+
"key": "Content-Security-Policy",
157+
"value": "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://api.iconify.design https://favicon.im; connect-src 'self' https://api.iconify.design; font-src 'self' data:;"
158+
}
159+
]
160+
}
161+
]
162+
}
163+
```
164+
165+
## 验证 CSP 配置
166+
167+
### 1. 使用浏览器开发者工具
168+
169+
1. 打开浏览器开发者工具(F12)
170+
2. 切换到"网络"(Network)标签
171+
3. 刷新页面
172+
4. 查看响应头中的 `Content-Security-Policy`
173+
174+
### 2. 测试 Iconify 功能
175+
176+
1. 打开编辑链接对话框
177+
2. 选择"Iconify图标"
178+
3. 搜索图标
179+
4. 如果能正常显示搜索结果,说明 CSP 配置正确
180+
181+
### 3. 检查控制台错误
182+
183+
如果 CSP 配置不正确,浏览器控制台会显示类似以下的错误:
184+
185+
```
186+
Refused to connect to 'https://api.iconify.design/...' because it violates the following Content Security Policy directive: "connect-src 'self'"
187+
```
188+
189+
190+
191+
```
192+
Refused to load the image 'https://api.iconify.design/...' because it violates the following Content Security Policy directive: "img-src 'self'"
193+
```
194+
195+
## 安全考虑
196+
197+
### 为什么需要允许 api.iconify.design?
198+
199+
- Iconify API 是一个可信的第三方服务
200+
- 提供开源图标的 CDN 服务
201+
- 使用 HTTPS 加密传输
202+
- 不会执行任何脚本,只提供图标数据
203+
204+
### 最小权限原则
205+
206+
建议的 CSP 配置遵循最小权限原则:
207+
208+
- 只允许必需的域名
209+
- 只允许必需的资源类型
210+
- 不允许不安全的内联脚本(除非必要)
211+
212+
### 替代方案
213+
214+
如果出于安全考虑不能允许外部 API 访问,可以考虑:
215+
216+
1. **自建 Iconify API 服务**
217+
- 部署自己的 Iconify API 实例
218+
- 更新 `NEXT_PUBLIC_API_ICONIFY_URL` 环境变量
219+
220+
2. **使用本地图标库**
221+
- 下载常用图标到项目中
222+
- 使用"自定义图标"功能上传本地图标
223+
224+
3. **禁用 Iconify 功能**
225+
- 只使用 Favicon 和自定义图标功能
226+
- 不需要修改 CSP 配置
227+
228+
## 故障排查
229+
230+
### 问题:图标搜索失败
231+
232+
**检查步骤:**
233+
234+
1. 打开浏览器控制台
235+
2. 查看是否有 CSP 相关错误
236+
3. 检查网络请求是否被阻止
237+
4. 验证 CSP 配置是否包含 `api.iconify.design`
238+
239+
### 问题:图标无法显示
240+
241+
**检查步骤:**
242+
243+
1. 检查 `img-src` 指令是否包含 `https://api.iconify.design`
244+
2. 查看浏览器控制台的错误信息
245+
3. 验证图标 URL 是否正确
246+
247+
## 更多资源
248+
249+
- [MDN: Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)
250+
- [CSP Evaluator](https://csp-evaluator.withgoogle.com/)
251+
- [Iconify API 文档](https://iconify.design/docs/api/)

0 commit comments

Comments
 (0)