#node.js #next.js
#node.js #next.js
Вопрос:
Я не хочу добавлять аутентификацию к какому-либо внешнему запросу или OAuth. Просто базовая аутентификация на стороне сервера для сервера узла.
На момент написания Next.js похоже, это не подтверждается: https://github.com/vercel/next.js/discussions/17719
Он поддерживает аутентификацию, но я предполагаю, что ее нужно будет добавлять к каждому отдельному маршруту приложения: https://nextjs.org/docs/authentication
Комментарии:
1. Вы действительно имеете в виду «(Basic Auth) [ developer.mozilla.org/en-US/docs/Web/HTTP/Authentication ] «? Это буквально просто HTTP-заголовок
Authorization
, представляющий собой версию user и pw на base64, и401
ответ, если он отсутствует, который должен запрашивать браузер пользователя. @Su-AuHwangHas отличный пример того, как это сделать.
Ответ №1:
— ОБНОВЛЕНО для NextJS 12.2 —
Текущая версия Nextjs позволяет запускать have add custom middleware, просто имея middleware.js/ts
файл в вашем root
каталоге (рядом с папкой pages). Там вы можете просто проверить Auth-заголовки и решить либо вызвать next
, чтобы разрешить это, либо вернуть код состояния 401, чтобы запретить это. Вот пример, скопированный из примера Nextjs (typescript)
import { NextRequest, NextResponse } from 'next/server'
export const config = {
matcher: '/',
}
export function middleware(req: NextRequest) {
const basicAuth = req.headers.get('authorization')
const url = req.nextUrl
if (basicAuth) {
const authValue = basicAuth.split(' ')[1]
const [user, pwd] = atob(authValue).split(':')
if (user === '4dmin' amp;amp; pwd === 'testpwd123') {
return NextResponse.next()
}
}
url.pathname = '/api/auth'
return NextResponse.rewrite(url)
}
вот ссылка на полный пример проекта:
https://github.com/vercel/examples/tree/main/edge-functions/basic-auth-password
— ДЛЯ БОЛЕЕ СТАРЫХ ВЕРСИЙ (до 12.2)—
Текущая версия Nextjs позволяет запускать have add custom middleware, просто имея _middleware.js/ts
файл в вашем pages
каталоге. Там вы можете просто проверить Auth-заголовки и решить либо вызвать next
, чтобы разрешить это, либо вернуть код состояния 401, чтобы запретить это. Вот пример, скопированный из примера Nextjs (typescript)
import { NextRequest, NextResponse } from 'next/server'
export function middleware(req: NextRequest) {
const basicAuth = req.headers.get('authorization')
if (basicAuth) {
const auth = basicAuth.split(' ')[1]
const [user, pwd] = Buffer.from(auth, 'base64').toString().split(':')
if (user === '4dmin' amp;amp; pwd === 'testpwd123') {
return NextResponse.next()
}
}
return new Response('Auth required', {
status: 401,
headers: {
'WWW-Authenticate': 'Basic realm="Secure Area"',
},
})
}
вот ссылка на полный пример проекта:
https://github.com/vercel/examples/tree/main/edge-functions/basic-auth-password
Комментарии:
1. Мне пришлось просто вызвать файл
middleware.ts
(без_
) и поместить его в корень моего Next.js приложение (неpages
включено), но затем оно сработало (как показано здесь: github.com/vercel/examples/tree/main/edge-functions /… ).2. @BennyNeugebauer ах да, спасибо, что указали на это, NextJS-промежуточное программное обеспечение вышло из бета-версии, и, к счастью, они отошли от маршрутизации на основе файлов, теперь вместо этого используется сопоставитель.
Ответ №2:
Редактировать: приведенное ниже решение ExpressJS не будет работать, если вы хотите разместить его, например, на Vercel, который стоит немного, но предлагает лучшее Next.js хостинг со встроенным пограничным кэшированием, масштабированием и оптимизацией изображений. Итак, если вы хотите разместить его на Vercel, чем добавлять аутентификацию к каждому отдельному маршруту, используя: https://nextjs.org/docs/authentication (может быть, не маленькие ножки, если не сделано с самого начала проекта).
Если вы, однако, намерены разместить его где-нибудь еще, который поддерживает Node.js и Express.js хостинг (и не предлагает ничего особенного для Next.js ) тогда приведенное ниже — отличное решение.
Решение ExpressJS:
Этот пост не распространяется на хранение базовых учетных данных аутентификации или использование нескольких учетных данных. Это скорее отправная точка, потому что я вообще ничего не смог найти в Google.
Мы будем использовать Express.js для размещения NextJS (в рабочем режиме!) в обоих примерах ниже.
Для запуска сервера в обоих примерах: node index.mjs
(в настоящее время используется node -v 14.9.0)
Сначала: создайте index.mjs
файл в корне.
(Вариант 1) Использование последней версии NextJS:
- Используйте последнюю версию (9.5 на момент написания) NextJS Express.js сервер узлов (в последней версии nextjs исправлены проблемы (я не проверял) с CSP https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP )
- Внутри index.mjs добавьте следующий код (установите необходимые модули):
import next from 'next'
import express from 'express'
import auth from 'basic-auth'
const dev = process.env.NODE_ENV === 'development'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare()
.then(() => {
const server = express()
server.use(function (req, res, next) {
const credentials = auth(req)
if (!credentials || credentials.name !== '[change_me_username]' || credentials.pass !== '[change_me_password]') {
res.status(401)
res.header('WWW-Authenticate', 'Basic realm="example"')
res.send('Access denied')
} else {
next()
}
});
server.get('*', (req, res) => {
return handle(req, res)
})
const port = 80;
server.listen(port, (err) => {
if (err) {
throw err
}
console.log(`Ready on http://localhost:${port}`)
})
})
.catch((ex) => {
console.error(ex.stack)
process.exit(1)
})
(Вариант 2) Использование NextJS 9.4 (если вы не можете обновить)
Этот ответ не касается потенциальных последствий от потенциальных целостностей безопасности CSP, лучший и самый простой способ справиться с этим — перейти на период NextJS 9.5.
- Внутри index.mjs добавьте следующий код (установите необходимые модули):
import next from 'next'
import express from 'express'
import auth from 'basic-auth'
const dev = process.env.NODE_ENV === 'development'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare()
.then(() => {
const server = express()
server.use(function (req, res, next) {
const credentials = auth(req)
if (!credentials || credentials.name !== '[change_me_username]' || credentials.pass !== '[change_me_password]') {
res.status(401)
res.header('WWW-Authenticate', 'Basic realm="example"')
res.send('Access denied')
} else {
// this is different from above NextJS 9.5, 9.4 requires inline js.
res.setHeader(
'Content-Security-Policy',
"default-src * 'self' data: 'unsafe-inline' *"
);
next()
}
});
server.get('*', (req, res) => {
return handle(req, res)
})
const port = 80;
server.listen(port, (err) => {
if (err) {
throw err
}
console.log(`Ready on http://localhost:${port}`)
})
})
.catch((ex) => {
console.error(ex.stack)
process.exit(1)
})
- Внутри
next.config.js
, если вы используетеnext-images
, в противном случае просто поместите объект:module.exports = { // ... }
const withImages = require('next-images')
module.exports = withImages({
async headers() {
return [
{
source: '/:path*',
headers: [
{
// // https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
key: 'Content-Security-Policy',
value: "default-src * 'self' data: 'unsafe-inline' *"
}
]
}
]
}
})