我想实现一下 SSR 功能,具体流程是这样,先是在登录页登录,然后调用 nextAuth 的 signin 方法,登录成功 token 会放到 session 里,之后跳转首页调用GetServerSideProps
,里面发起 fetch 拿数据。
但是在第一次进入首页时发现GetServerSideProps
中利用 nextAuth 的 apigetSession
获取的 session 是 null ,组件内部能获得,并且 terminal 报错message: 'decryption operation failed'
。但是一刷新后 session 又能正常获得了,控制台也没有报错,不知道有没有人遇到过和我一样的情况?代码如下:
// [...nextauth].ts
export default NextAuth({
session: {
strategy: "jwt",
},
providers: [
CredentialsProvider({
name: "xxx",
id: "credentials",
credentials: {
phone: {
label: "手机号",
type: "text",
},
code: { label: "验证码", type: "text" },
},
async authorize(credentials) {
const params = {
phone: credentials?.phone ?? "",
code: credentials?.code ?? "",
};
const env = process.env.H5_OPERATION_ENV || process.env.NODE_ENV;
let host;
switch (env) {
case "DEV":
host = "xxx";
break;
case "qa":
host = "xxx";
break;
case "prod":
host = "xxx;
break;
default:
break;
}
const res = await request.get(
xxx,
{ params }
);
const user = await res.payLoad;
if (res.status === "SUCCESS" && user) {
return user;
} else {
throw new Error(res.error);
}
},
}),
],
pages: {
signIn: "/Login/",
},
callbacks: {
async jwt({ token, user }) {
if (user) {
token.accessToken = (user as any)?.accessToken;
token.name = (user as any)?.loginUserName as string;
}
return token;
},
async session({ session, token }) {
(session as Session & { accessToken: string | undefined }).accessToken =
token.accessToken as string;
if (session.user) {
session.user.name = token.name as string;
}
return session;
},
signIn({ user }) {
request.interceptors.request.use((url, opts) => {
let headers: { Authorization?: string } = {};
if ((user as any)?.accessToken) {
headers.Authorization = `API-Bearer ${(user as any).accessToken}`;
}
return {
url,
options: { ...opts, ...headers },
};
});
return true;
},
},
secret: process.env.NEXTAUTH_SECRET,
debug: true,
});
// .env.development
H5_OPERATION_ENV = DEV
NEXTAUTH_URL_INTERNAL = http://localhost:3000/
NEXTAUTH_URL = http://localhost:3000/
NEXTAUTH_SECRET = xxx
// login.tsx
const login = async (values: any) => {
const res = await signIn('credentials', { ...values, redirect: false })
if (res?.ok) {
const session = await getSession()
getUserAuth({ currentUser: session?.user?.name ?? '' }).then(res => {
if (res?.status === 'SUCCESS') {
dispatch({ type: 'setState', payload: { powerList: res?.payLoad?.powerList?.map((power: any) => power?.powerCode) } })
}
})
router.push('/home')
}
//home.tsx
export const getServerSideProps: GetServerSideProps<IndexProps> = async context => {
const session = await getSession(context);
console.log(session, 'first getServerSideProps'); // 第一次进入返回了 null
let data: never[] = []
if ((session as any)?.accessToken) {
console.log(session, 'getServerSidePropsGetSession');
const res = await fetch(`http://xxx`, {
headers: {
Authorization: `API-Bearer ${(session as any).accessToken}`
}
})
await res?.json().then(response => {
console.log(data, 'json()');
if (response.status === 'SUCCESS') {
data = response.payLoad.list
}
})
}
return {
props: {
list: JSON.stringify(data) ?? []
}
}
}
export default function Home(props: IndexProps) {
const { data: session } = useSession() // 这里是 ok 的
}
// package.json
"next": "12.2.3",
"next-auth": "^4.10.3",
1
violetlai 2023-01-19 15:31:53 +08:00
感觉你的登录流程有点奇怪,主要需求是 token 持久化?
最近我也在做 ssr 只不过使用了 Nuxt3 ,登录流程是客户端发请求=》服务端处理返回结果 token=》保存 session=》 redis?=》 set-cookie=》拿 cookie 可以参考下 |