如何向NextAuth的signIn回调传递自定义参数以区分账号操作?
问题描述
我正在用NextAuth实现谷歌账号登录/注册,以及谷歌账号关联站点现有账号的功能。为了区分未登录时的注册操作和已登录时的账号关联操作,我想给signIn方法传一个额外参数,在signIn回调里拿到并执行对应逻辑。我试了下面的代码:
signIn("google", null, { linkAccount: "true" });
但这个参数只作为查询参数传入signIn请求,没法传到回调里。请问怎么让自定义参数在回调中能访问到?
补充代码
调用NextAuth的signIn客户端API:
signIn("google", null, { linkAccount: "true" });
[...nextauth.js]文件代码:
import NextAuth from 'next-auth'; import GoogleProvider from 'next-auth/providers/google'; import axios from 'axios'; const authOptions = (req) => ({ providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, }), ], secret: "secret", callbacks: { async signIn({ user, account, profile, email, credentials }) { // 目标:如何告知该端点我仅需关联账号? let res = await axios.post('http://localhost:8000/users/third_party_sign_in', { third_party_id: user.id, email: user.email, type: account.provider, justLink: true|false // 需要根据自定义参数设置这个值 }, { withCredentials: true }) let path; if (res.data.action === "login") { path = `/?action=${res.data.action}&id=${res.data.user_id}&email=${user.email}&third_party=${account.provider}` } else if (res.data.action === "create") { path = `/?action=${res.data.action}&name=${user.name}&email=${user.email}&third_party=${account.provider}&third_party_id=${user.id}` } return path; }, async redirect({ url }) { return Promise.resolve(url) } }, }); function testNextApiRequest(req) { if (req.query.nextauth && req.query.nextauth.length === 2 && req.query.linkAccount) { /// signIn API调用时会打印,但回调时不会 console.log("QUERY PARAMS: ", req.query); } } export default (req, res) => { testNextApiRequest(req); return NextAuth(req, res, authOptions(req)); }
解决方案
要让自定义参数能传递到signIn回调里,你可以利用NextAuth的state参数来携带自定义数据——OAuth授权流程中state会被自动保留并传递回回调,完美解决参数丢失的问题。具体操作如下:
1. 客户端调用signIn时传入state参数
修改客户端的signIn调用,把自定义参数序列化后放到state字段里:
signIn("google", null, { state: JSON.stringify({ linkAccount: "true" }) });
2. 在signIn回调中解析state参数
在signIn回调里,从account.state取出之前传入的内容,解析后就能拿到自定义参数:
async signIn({ user, account, profile, email, credentials }) { // 解析state中的自定义参数,处理空值情况 const state = account.state ? JSON.parse(account.state) : {}; const justLink = state.linkAccount === "true"; let res = await axios.post('http://localhost:8000/users/third_party_sign_in', { third_party_id: user.id, email: user.email, type: account.provider, justLink: justLink // 用解析后的参数赋值 }, { withCredentials: true }) // 后续跳转逻辑保持不变... }
为什么之前的方法无效?
你之前直接传自定义参数,只会出现在初始的signIn请求查询参数里,但OAuth流程需要跳转到谷歌授权页面,跳转回来后初始查询参数会丢失,所以回调里拿不到。而state是OAuth规范里的标准字段,NextAuth会自动帮你在整个流程中保留这个参数,授权完成后会把它附在account对象里返回,所以能稳定传递自定义数据。
内容的提问来源于stack exchange,提问作者Nathan
相关产品推荐
相关产品推荐

