Ale*_*sen 4 javascript authentication auth0 next.js
我目前正在努力在更新 user_metadata 后从 Auth0 重新获取用户数据:
下面是一个简化的 索引文件。用户选择某个对象,系统会要求将此对象(或对象 ID)添加为收藏夹。如果用户想要选择该对象作为收藏夹,我们需要更新 user_metadata 中的首选项。
// index.tsx
export default function home({user_data, some_data}) {
const [selected, setSelect] = useState(null)
async function handleAddToFavourite() {
if (selected) {
const data = await axios.patch("api/updateMetadata", {some_favorite: selected.id})
// Errorhandling ...
}
}
return (
<div>
<SearchData setData={setSelect} data={some_data}/>
<Button onClick={handleAddToFavorite}>Add to Favorite</Button>
<div>Selected: {selected.id}</div>
<div>My Favorite: {user_data.user_metadata.some_favorite}</div>
</div>
)
}
export const getServerSideProps = withPageAuthRequired({
returnTo: "/foo",
async getServerSideProps(ctx) {
const session = await getSession(ctx.req, ctx.res)
const {data} = await axios.get("https://somedata.com/api")
return {props: {some_data: data, user_data: session.user}}
})
Run Code Online (Sandbox Code Playgroud)
然后,请求被发送到pages/api/updateMetadata,并且user_metadata将使用所选数据进行更新。
// api/updateMetadata.ts
async function handler(req: NextApiRequest, res: NextApiResponse) {
const session = await getSession(req, res);
if (!session || session === undefined || session === null) {
return res.status(401).end();
}
const id = session?.user?.sub;
const { accessToken } = session;
const currentUserManagementClient = new ManagementClient({
token: accessToken,
domain: auth0_domain.replace('https://', ''),
scope: process.env.AUTH0_SCOPE,
});
const user = await currentUserManagementClient.updateUserMetadata({ id }, req.body);
return res.status(200).json(user);
}
export default withApiAuthRequired(handler);
Run Code Online (Sandbox Code Playgroud)
[...auth0].tsx 看起来像这样。
// pages/api/auth/[...auth0].tsx
export default handleAuth({
async profile(req, res) {
try {
await handleProfile(req, res, {
refetch: true,
});
} catch (error: any) {
res.status(error.status || 500).end(error.message);
}
},
async login(req, res) {
try {
await handleLogin(req, res, {
authorizationParams: {
audience: `${process.env.AUTH0_ISSUER_BASE_URL}/api/v2/`,
scope: process.env.AUTH0_SCOPE,
},
});
} catch (error: any) {
res.status(error.status || 400).end(error.message);
}
},
});
Run Code Online (Sandbox Code Playgroud)
现在,我每次登录时都会获取 user_metadata,但是,我需要注销并登录才能看到更改生效。每次更新 user_metadata 时,我都需要以某种方式刷新用户会话而不注销。
有谁知道实现我想要做的事情的任何解决方法,并且可能看到任何错误?
笔记:
我尝试使用客户端函数useUser(),但这会产生与getSession()index.tsx 中 user_data 的服务器端函数相同的数据
我尝试updateSession(req, res, session)在 api/updateMetadata 处理程序的末尾添加
我已将操作添加到 Auth0 登录流程
// Auth0 action flow - login
exports.onExecutePostLogin = async (event, api) => {
const namespace = 'https://example.com';
const { some_favorite } = event.user.user_metadata;
if (event.authorization) {
// Set claims
api.idToken.setCustomClaim(`${namespace}/some_favorite`, );
}
};
Run Code Online (Sandbox Code Playgroud)
我想通了,我会发布我的解决方案,以防其他人遇到同样的问题:)
在 api/updateMetadata.ts 中:
// api/updateMetadata.ts
import { updateSession , ... } from '@auth0/nextjs-auth0';
// ...
// ...
const user = await currentUserManagementClient.updateUserMetadata({ id }, req.body);
await updateSession(req, res, { ...session, user }); // Add this to update the session
return res.status(200) // ...
Run Code Online (Sandbox Code Playgroud)
然后,在获取数据后,我立即在客户端代码中使用 useUser 中的 checkSession() 。
// index.tsx
import { useUser } from '@auth0/nextjs-auth0/client'
//...
const { user, checkSession } = useUser();
async function handleAddToFavourite() {
if (selected) {
const data = await axios.patch("api/updateMetadata", {some_favorite: selected.id})
// Update the user session for the client side
checkSession()
// Errorhandling ...
}
}
//...
Run Code Online (Sandbox Code Playgroud)
现在,这就是使一切正常工作的原因,修改 profileHandler:
// pages/api/auth/[...auth0].tsx
// Updating with the new session from the server
const afterRefetch = (req, res, session) => {
const newSession = getSession(req, res)
if (newSession) {
return newSession as Promise<Session>
}
return session
}
export default handleAuth({
async profile(req, res) {
try {
await handleProfile(req, res, {
refetch: true,
afterRefetch // added afterRefetch Function
});
} catch (error: any) {
res.status(error.status || 500).end(error.message);
}
},
// ...
});
Run Code Online (Sandbox Code Playgroud)
另外,值得注意的是,登录的 Auth0 操作流程也是正确的。
希望这对某人有帮助:)