reactjs 如何在不注销的情况下更新会话值?

vatpfxk5  于 2023-01-17  发布在  React
关注(0)|答案(4)|浏览(127)

对于NextAuth.js,如何在不注销和再次登录的情况下更新会话对象中的值?
例如,一旦用户登录,我就使用存储在会话中的URL来显示用户的化身。
我还提供用户更改他的化身,所以我希望session.user.image能够更新并保持化身的新路径。我将所有数据存储在MongoDB中。我如何实现这一点?目前唯一的解决方案是要求用户注销并重新登录,但这听起来不像是一个我可以接受的解决方案:)
我的第一个想法是,一旦用户更新了他的化身,就更新这个会话对象,但我不知道如何做到这一点。

import React from 'react'
import { signIn, signOut, useSession } from 'next-auth/client'

export default function Page() {
  const [ session, loading ] = useSession()

  return <>
    {session && <>
      <img src={session.user.image} />
      <button onClick={signOut}>Sign out</button>
    </>}
  </>
}
ryevplcw

ryevplcw1#

你能做的最好的事情是在发送会话数据到客户端之前修改数据。通过使用next-auth会话回调,我们可以很容易地做到这一点。

callbacks: {
      session: async (session, user) => {
      
        const userDatabase = await CreateAccount.findOne({
          email: user.email,
        }); //finding user in DB.
        
        const userData = {
          name: userDatabase.username,
          email: userDatabase.email,
          image: userDatabase.avatar,
          id: userDatabase._id,
        } // creating payload
        
        session.user = userData; //sending payload as session
        
        return Promise.resolve(session);
      },
    },
swvgeqrz

swvgeqrz2#

一种可能的解决方案是手动更新用户对象,查看下面的链接了解next-auth的回调函数是如何工作的https://next-auth.js.org/configuration/callbacks-一种可能的方法是在jwt()/session()回调函数中更新用户,并自行调整用户信息。
到目前为止,我还没有找到一个函数来触发与数据库相关的用户对象的自动更新。

qqrboqgw

qqrboqgw3#

在我的情况下,我在我的网站上做apment之后,我想修改会话时,我做的会话。用户。订阅=真;它的作品,如果我不重新加载页面,当我重新加载页面,我得到previos值订阅=假,现在根据u,我可以n=修改会话通过用户在回调,但我怎么能知道,付款已在这些回调,我们被困在这一刻.
如果我注销并重新登录,会话中订阅者值将自动更新

fcipmucu

fcipmucu4#

通常不建议在提供程序的配置之外修改会话,因为这可能导致安全问题,如篡改用户数据。
如果将next-auth会话存储在数据库中(即session.strategy = "database"),那么最好的选择可能是直接在数据库中更新会话。
但是,如果您将会话存储在next-auth的加密JWT中,那么重新验证用户并发布一个具有更新信息的新JWT可能是最安全的方法。

也就是说,您可以通过以下方式直接更新JWT标记

1.从“next-auth.session-token”cookie中获取当前令牌值
1.更新令牌
1.基于更新的令牌和旧值(如过期、发布时间、...)创建新的加密JWT
1.将“next-auth.session-token”cookie值替换为新的内标识
下面是一个示例,它看起来是这样的:

// pages/api/update-user-to-premium.js

import { EncryptJWT } from "jose";
import hkdf from "@panva/hkdf";
import { serialize } from "cookie";
import { getToken } from "next-auth/jwt";

export default async function handler(req, res) {
    // 1. Get current token
    const token = await getToken({ req });
    // Example structure of the "token"
    // {
    //     sub: '{3d19bdd6-4764-40e6-b09e-41x7029bceed}',
    //     email: 'example@example.com',
    //     isPremiumUser: false
    //     iat: 1673862936,
    //     exp: 1676454936,
    //     jti: '881e5517-90b6-4430-8270-60f0b880f996'
    // }

    // 2. Update the token except "sub", "iat", "exp" and "jti"
    token.isPremiumUser = true;

    // 3. Create a new encrypted JWT token with the updated value(s)
    const newToken = await encode(token, process.env.NEXTAUTH_SECRET);

    // 4. Replace the next-auth session cookie with the new value
    const cookie = serialize("next-auth.session-token", newToken, {
        httpOnly: true,
        path: "/",
        maxAge: token.exp,
        sameSite: "lax",
    });
    res.setHeader("Set-Cookie", cookie);

    res.status(200).json({ message: "Successfully updated user to premium" });
}

/**
 * Modify "next-auth" encode method to manullay set JWT claims
 * @see https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/jwt/index.ts#L17
 */
async function encode(token, secret) {
    const encryptionSecret = await getDerivedEncryptionKey(secret); // Create a cryptographical random secret key using a predictable random secret.
    return await new EncryptJWT(token)
        .setProtectedHeader({ alg: "dir", enc: "A256GCM" })
        .setSubject(token.sub) // set "sub" Subject claim
        .setIssuedAt(token.iat) // adds "iat" to the JWT with current timestamp
        .setExpirationTime(token.exp) // adds "exp" to the JWT - timestamp format
        .setJti(token.jti) // set the "jti claim" - allows for replay protection/blacklist
        .encrypt(encryptionSecret);
}

/**
 * Copy & Paste from "next-auth" since it's not exported
 * Create a cryptographical random secret key using a predictable random secret.
 * @see https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/jwt/index.ts#L119
 * @param {string} secret Random string secret, e.g. "Whale-Banana-69"
 * @returns {Promise<Uint8Array(32)>} Actual cryptographical randomnes, e.g. transforms above into: "Uint8Array(32) [189,67,29,228,...]" which
 */
async function getDerivedEncryptionKey(secret) {
    return await hkdf(
        "sha256",
        secret,
        "",
        "NextAuth.js Generated Encryption Key",
        32
    );
}

上面的代码使用next-auth的内部encode方法,该方法基于derived encryption key创建加密的JWT,而不是使用普通的NEXTAUTH_SECRET值进行加密。
由于next-auth使用HttpOnly cookie,因此此代码显然仅在API路由中工作,出于安全考虑,显然不应尝试使其在客户端工作。

相关问题