V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
philsky28
V2EX  ›  问与答

有人在 next.js 中用过 nextAuth 吗?想问个问题

  •  1
     
  •   philsky28 · 2023-01-19 14:25:57 +08:00 · 1608 次点击
    这是一个创建于 711 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我想实现一下 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",
    
    2 条回复    2023-01-19 17:11:21 +08:00
    violetlai
        1
    violetlai  
       2023-01-19 15:31:53 +08:00
    感觉你的登录流程有点奇怪,主要需求是 token 持久化?

    最近我也在做 ssr 只不过使用了 Nuxt3 ,登录流程是客户端发请求=》服务端处理返回结果 token=》保存 session=》 redis?=》 set-cookie=》拿 cookie
    可以参考下
    philsky28
        2
    philsky28  
    OP
       2023-01-19 17:11:21 +08:00
    @violetlai 是为了 token 持久化,以前直接放在了 localStorage 里,但是用 SSR 时,getserversideprops 方法中实际环境是服务端,没法拿到浏览器环境的 token ,所以现在改用 session 存储
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1114 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 18:42 · PVG 02:42 · LAX 10:42 · JFK 13:42
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.