Before deciding to use a custom server, please keep in mind that it should only be used when the integrated router of Next.js can't meet your app requirements. A custom server will remove important performance optimizations, like serverless functions and Automatic Static Optimization.
背景
我有一个文档网站,底层技术用的是 NextJS,所有页面都是 build time 生成,最终都是静态页面。我想要实现这样的效果:
假设用户起初访问的是 /welcome,因为没有登录,所以跳转到 /sign_in?redirect=welcome。登录成功,则跳转到 /welcome 页面。
不太理想的尝试
对于 Auth ,NextJS 官网给了两种思路。第一种,页面load到浏览器后,用浏览器 js 判定登录状态和跳转。第二种,用 server page 判定登录状态和跳转。 第一种方案,实现比较简单,问题是 page props 会先 load 到页面,再判定登录状态和跳转。存在敏感数据泄露的可能,不能满足数据保护的要求。 第二种方案,实现稍微要复杂一些,也能达到数据保护的目的。但是相应的,会失去静态页面的便利性和安全性。得不偿失。
为什么不定制 NextJS Server
通过替换 NextJS 标准 server,加入拦截逻辑,也可以做到判定登录,以及跳转,官网中的示例表明这是一种可行的做法。https://nextjs.org/docs/advanced-features/custom-server。但这是有代价的,对我来说非常重要的 static gen 功能会得到削弱(具体数值没测试过)
所以,思考再三,我决定跳出 NextJS ,寻找一种更加简便的办法:它应该足够解耦,不需要修改 NextJS 的 server,或者 page generation。这并不需要花费很多力气,现在毕竟不是互联网的蛮荒时期,啥都没有。我很快就找到了自己的目标: Nginx。
Nginx
首先,NextJS 这里准备一个 auth api,比如 /api/auth,用来判定 http 请求携带的 cookie 是否包含合法可用的 token。 然后,通过 Nginx 的 auth_request_module,拦截请求,转发给 /api/auth 处理,然后根据返回状态码,跳转到 sign_in 或者其他页面。 以下是 Nginx 的配置(忽略 server 的其他无关主题的配置)。 注:http://localhost:3030 是 NextJS App 的地址。
简单解释一下:
结论
NextJS 本身无法兼顾静态和服务端鉴权,此时,可以将鉴权交由 Nginx 负责,通过它的 auth request 模块来转发请求,处理鉴权结果。 参考资料:
ps. Nginx 的 tag 居然是存在的,这证明之前也写过 Nginx 相关的东西。感觉每次都是 Nginx 救场,哈哈。