查看: 59|回覆: 0

记一次通过宝塔和 Docker 部署 Next.js 项目时关闭 Basic Auth 的过程

[複製鏈接]

3

主題

0

回帖

0

積分

热心网友

金币
0
閲讀權限
220
精華
0
威望
0
贡献
0
在線時間
0 小時
註冊時間
2011-8-10
發表於 2026-4-17 11:46:00 | 顯示全部樓層 |閲讀模式

背景

这次在一台已经安装宝塔面板的 Linux 服务器上部署一个 Next.js 项目。

项目本身是:

  • Next.js 14

  • Docker Compose 部署

  • Nginx 反向代理

  • /admin/api/content/api/upload/api/upload-logo这些路径通过middleware做了 HTTP Basic Auth 保护

部署完成后,前台页面可以打开,但是访问后台时浏览器会弹出原生登录框,并提示“您与此网站的连接不是私密连接”。

这次排查的目标很明确:先把项目正常部署起来,然后关闭 Basic Auth,避免浏览器再弹原生认证框。

一、最开始遇到的问题是什么

当时访问的是:

http://<IP>:8080/admin

浏览器会弹出 Basic Auth 登录框,并提示连接不私密。

这里要先分清楚两件事:

  1. 这不是程序报错

  2. 这是浏览器对“HTTP 明文连接下输入账号密码”的安全提醒

只要继续使用:

HTTP + Basic Auth

这个提示就很难消除。

二、项目原来的鉴权是怎么做的

项目里用的是 Next.js middleware,大致逻辑如下:

import type { NextRequest } from 'next/server'
import { NextResponse } from 'next/server'

const authRealm = 'Portfolio Admin'

const unauthorizedResponse = () =>
  new NextResponse('Authentication required', {
    status: 401,
    headers: {
      'WWW-Authenticate': `Basic realm="${authRealm}", charset="UTF-8"`,
    },
  })

export function middleware(request: NextRequest) {
  const username = process.env.ADMIN_USERNAME
  const password = process.env.ADMIN_PASSWORD

  // 读取 authorization 头并校验
  // 校验失败则返回 401
}

export const config = {
  matcher: [
    '/admin',
    '/admin/:path*',
    '/api/content',
    '/api/content/:path*',
    '/api/upload',
    '/api/upload/:path*',
    '/api/upload-logo',
    '/api/upload-logo/:path*',
  ],
}

从这里可以看出:

  • /admin受 Basic Auth 保护

  • 内容保存接口和上传接口也一起受保护

所以只要这个中间件还生效,访问/admin就一定会弹浏览器原生认证框。

三、第一次尝试:想通过环境变量关闭 Basic Auth

一开始我的想法是,不直接删掉鉴权逻辑,而是加一个开关,例如:

const authEnabled = process.env.ADMIN_AUTH_ENABLED !== 'false'

if (!authEnabled) {
  return NextResponse.next()
}

然后在生产环境变量里加:

ADMIN_AUTH_ENABLED=false

这个思路本身没有问题,优点也很明显:

  • 改动小

  • 可回滚

  • 后续想重新开启鉴权时,只需要改环境变量

但是实际上,容器重建后访问/admin仍然返回401,说明 Basic Auth 依旧在生效。

四、为什么环境变量方案没有达到预期

这一步最麻烦的地方在于:源码看起来已经改对了,环境变量也已经写进.env.production了,但运行结果不对。

当时做了几轮确认:

  1. 确认服务器源码目录里的src/middleware.ts已经包含ADMIN_AUTH_ENABLED

  2. 确认.env.production已经有:

    ADMIN_AUTH_ENABLED=false
    
  3. 确认容器确实已经重建

  4. 确认容器内ADMIN_USERNAMEADMIN_PASSWORD仍然存在

  5. 继续检查.next里的编译产物,确认中间件打包后的代码里也确实出现了ADMIN_AUTH_ENABLED

到这里说明一个问题:这不是“代码没同步上去”,也不是“环境变量没传进去”,而是这个关闭开关在实际构建和运行链路里没有按预期生效。

五、第二次尝试:直接移除 Basic Auth 逻辑

因为这次的目标不是“做一个长期可配置的后台认证方案”,而是“先把浏览器原生 Basic Auth 登录框关掉”,所以后面改成了更直接的处理方式:

middleware.ts改成无条件放行。

最终改成这样:

import { NextResponse } from 'next/server'

export function middleware() {
  return NextResponse.next()
}

export const config = {
  matcher: [
    '/admin',
    '/admin/:path*',
    '/api/content',
    '/api/content/:path*',
    '/api/upload',
    '/api/upload/:path*',
    '/api/upload-logo',
    '/api/upload-logo/:path*',
  ],
}

这里有一个细节:

  • matcher还保留着

  • 只是这些路径命中后不再做认证,而是直接放行

这样做的好处是:

  • 不影响中间件匹配范围

  • 不需要额外改页面或接口代码

  • 行为足够直接,结果容易验证

最后重新构建镜像并启动容器后正常。

六、最终结论

一句话总结:

浏览器里的 Basic Auth 登录框,本质上是服务端返回了401 + WWW-Authenticate;只要中间件不再返回这个响应,弹框自然就消失了。

当然,这只是这次的临时方案,如果要保证后台安全则需要留下认证。



来源:https://www.cnblogs.com/Higurashi-kagome/p/19882396
回覆

使用道具 舉報

您需要登錄後才可以回帖 登錄 | 立即注册

本版積分規則

相关侵权、举报、投诉及建议等,请发 E-mail:qiongdian@foxmail.com

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部