【发布时间】:2022-01-17 20:13:24
【问题描述】:
我有一个简单的应用程序,我在其中使用 NextAuth 进行身份验证。我使用 spotify 提供程序,并且在我的开发环境中一切正常。但是,当我在服务器上的 docker 中运行我的应用程序时,它不会。
这是我的 _app.jsx:
import "../styles/globals.css"
import { SessionProvider } from "next-auth/react"
import { RecoilRoot } from "recoil"
function MyApp({ Component, pageProps }) {
return (
<SessionProvider session={pageProps.session}>
<RecoilRoot>
<Component {...pageProps} />
</RecoilRoot>
</SessionProvider>
)
}
export default MyApp
_middleware.jsx:
import { getToken } from "next-auth/jwt"
import { getSession } from "next-auth/react"
import { NextResponse } from "next/server"
export async function middleware(req) {
const session = await getToken({
req,
secret: process.env.SECRET,
secureCookie: true
})
const { pathname } = req.nextUrl
if (pathname.includes("/api/auth") || session) {
return NextResponse.next()
}
if (!session && pathname !== "/login") {
return NextResponse.redirect("/login")
}
}
index.jsx
export default function Home() {
return (
<div className="bg-black h-screen overflow-hidden">
<main className="flex">
<Sidebar />
<Center />
</main>
<div className="sticky bottom-0">
<Player />
</div>
</div>
)
}
export async function getServerSideProps(ctx) {
return {
props: {
session: await getSession(ctx)
}
}
}
[...nextauth].js
import NextAuth from "next-auth"
import SpotifyProvider from "next-auth/providers/spotify"
import spotifyApi, { LOGIN_URL } from "../../../lib/spotify"
async function refreshAccessToken(token) {
try {
spotifyApi.setAccessToken(token.accessToken)
spotifyApi.setRefreshToken(token.refreshToken)
const { body: refreshedToken } = await spotifyApi.refreshAccessToken()
console.log("REFRESHED TOKEN IS", refreshedToken)
return {
...token,
accessToken: refreshedToken.access_token,
accessTokenExpires: Date.now() + refreshedToken.expires_in * 1000, // = 1 hour as 3600 returns from spotify API
refreshToken: refreshedToken.refresh_token ?? token.refreshToken
}
} catch (error) {
console.error(error)
return {
...token,
error: "RefreshAccessTokenError"
}
}
}
export default NextAuth({
// Configure one or more authentication providers
providers: [
SpotifyProvider({
clientId: process.env.NEXT_PUBLIC_CLIENT_ID ?? "NO_CLIENT_ID",
clientSecret: process.env.NEXT_PUBLIC_CLIENT_SECRET ?? "NO_CLIENT_SECRET",
authorization: LOGIN_URL
})
// ...add more providers here
],
session: {
strategy: "jwt"
},
secret: process.env.JWT_SECRET,
pages: {
signIn: "/login"
},
callbacks: {
async jwt({ token, account, user }) {
// initial sign in
if (account && user) {
return {
...token,
accessToken: account.access_token,
refreshToken: account.refresh_token,
username: account.providerAccountId,
accessTokenExpires: account.expires_at * 1000
}
}
if (Date.now() < token.accessTokenExpires) {
console.log("EXISTING ACCESS TOKEN IS VALID!")
return token
}
// refresh access token (imagine having a expired token pfff)
console.log("ACCESS TOKEN HAS EXPIRED! REFRESHING...")
return await refreshAccessToken(token)
},
async session({ session, token }) {
session.user.accessToken = token.accessToken
session.user.refreshToken = token.refreshToken
session.user.username = token.username
return session
}
}
})
然后我在本地使用这个 .env.local 文件:
NEXTAUTH_URL=http://localhost:3000
NEXT_PUBLIC_CLIENT_SECRET=[MY_SECRET]
NEXT_PUBLIC_CLIENT_ID=[MY_CLIENT_ID]
JWT_SECRET=[MY_JWT_SECRET]
在生产中我使用这个 Dockerfile:
FROM node:16-alpine AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json ./
RUN yarn install --frozen-lockfile
FROM node:16-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN yarn build
# Production image, copy all the files and run next
FROM node:16-alpine AS runner
WORKDIR /app
ENV NODE_ENV production
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
COPY --from=1 /app/next.config.js ./
COPY --from=1 /app/public ./public
COPY --from=1 --chown=nextjs:nodejs /app/.next ./.next
COPY --from=1 /app/node_modules ./node_modules
COPY --from=1 /app/package.json ./package.json
USER nextjs
EXPOSE 3000
CMD ["yarn", "start"]
连同这个 docker-compose.yml 文件:
version: "3.3"
services:
next-app:
image: ghcr.io/my-username/my-app:latest
ports:
- "3000:3000"
restart: unless-stopped
environment:
- NEXT_PUBLIC_CLIENT_SECRET=[...]
- NEXT_PUBLIC_CLIENT_ID=...]
- NEXTAUTH_URL=https://mydomain.dev
- JWT_SECRET=[...]
所以,上面的代码在我的 localhost 环境中运行良好,但在我的服务器上却无法运行。当我登录时,我确实收到以下控制台消息:“现有访问令牌有效!”你可以在[...nextauth] 中看到,但是在_middleware.js 中,会话值始终为空,所以我停留在登录页面。
我已经尝试在 nextAuth 中使用调试选项运行,但是没有错误消息或类似的东西。所以,我想知道:什么可能导致这个问题,我该如何解决?
可能值得注意:部署到 vercel 时问题是相同的。所以它可能与 docker 无关。
【问题讨论】:
-
你在中间件代码中使用
process.env.SECRET,SECRET在Docker中设置在哪里? -
哇...是的,令人难以置信的是,这就是问题所在...感谢您抓住那个
标签: reactjs docker next.js next-auth