Где и как изменить объект пользователя сеанса после входа в систему?
У меня странная проблема, и я не знаю, в чем проблема. Я использую библиотеку next-auth, чтобы сделать систему аутентификации в моем
Next.js
приложение.
Все в порядке - могу войти, проверив, есть ли аккаунт в
google firebase
с предоставленными учетными данными,
session
создается правильно, но когда
authorize
обратный вызов инициализирован Я передаю данные, полученные от
google firestore
после правильного входа в систему. Пользовательский объект содержит все данные и передается вперед.
Затем, когда я захочу прочитать данные из
session
, некоторые данные, которые я передал ранее, отсутствуют.
Код:
/pages/api/auth/[...nextauth.js]
export default (req, res) =>
NextAuth(req, res, {
providers: [
Providers.Credentials({
name: 'Credentials',
credentials: {
phone: { label: "Phone number", type: "text" },
password: { label: "Password", type: "password" }
},
authorize: async (loginData) => {
const { csrfToken, phone, password } = loginData;
// checking if there is account with these credentials
let res = await login({
phone,
password: sha1(md5(password)).toString()
})
// 200 = OK
if(res.status == 200){
// collect account data
const user = {
phone,
...res.data.info
}
// user object is created correctly, whole data is stored there
console.log('received account data from firestore', user)
return Promise.resolve(user);
}
else {
// wrong credentials
return Promise.resolve(null);
}
}
})
],
callbacks: {
session: async (session, user) => {
console.log('data passed to object when signed in', user)
// user object there doesn't have all data passed before
return Promise.resolve(session)
}
},
debug: false
})
Объекты, регистрируемые в консоли:
received account data from firestore
{
phone: '123123123',
id: 'w2zh88BZzSv5BJeXZeZX',
email: 'jan@gmail.com',
name: 'Jan',
surname: 'Kowalski'
}
data passed to object when signed in
{
name: 'Jan',
email: 'jan@gmail.com',
iat: 1603900133,
exp: 1606492133
}
Лучше всего то, что объект (см. Выше) всегда имеет одни и те же свойства. Я могу передать любой объект в
authorize
обратный вызов, но в
session
,
user
объект всегда имеет "name, email, iat, exp" ВСЕГДА. Единственное, что изменяется, - это значения этих двух свойств в объекте (имя, адрес электронной почты). (остальные свойства - "телефон, идентификатор, фамилия" - отсутствуют).
Ниже находится консоль в логе
session
объект в любом компоненте реакции:
import {
signIn,
signOut,
useSession
} from 'next-auth/client'
const [ session, loading ] = useSession();
console.log(session)
Фотография объекта консольного сеанса
Что я могу сделать? Должен ли я получать данные от
firestore
отдельно в
session
Перезвони? Рендеринг на стороне сервера
Next.js
вызывая проблему?
2 ответа
Я решил эту проблему сам.
Эта тема мне очень помогла!
https://github.com/nextauthjs/next-auth/issues/764
Ниже приводится объяснение:
callbacks: {
jwt: async (token, user, account, profile, isNewUser) => {
// "user" parameter is the object received from "authorize"
// "token" is being send below to "session" callback...
// ...so we set "user" param of "token" to object from "authorize"...
// ...and return it...
user && (token.user = user);
return Promise.resolve(token) // ...here
},
session: async (session, user, sessionToken) => {
// "session" is current session object
// below we set "user" param of "session" to value received from "jwt" callback
session.user = user.user;
return Promise.resolve(session)
}
}
У меня тоже была эта проблема, и, как выяснилось, проблемы были вызваны функциями адаптера. В моем случае я хотел использовать v4 next-auth, и я хотел использовать DynamoDB. Поскольку официального адаптера v4 для Dynamo нет, мне пришлось написать свой собственный, основанный на общедоступном адаптере v3 .
Одна из функций, которые вы должны предоставить при создании собственного адаптера :
async updateUser(user) {
// use ddb client to update the user record
// client returns `data`
return { ...user, ...data.Attributes }
}
Оказывается, данные в
data.Attributes
это то, что передается вашему обратному вызову как. Похоже, это отличается от реализации v3.
Поэтому в моем случае мне пришлось структурировать функцию адаптера Dynamodb, чтобы дать клиенту команду возвращать ALL_NEW, а не просто UPDATED_NEW (что и делает адаптер v3).
Моя полная
updateUser()
функция выглядит следующим образом - имейте в виду, что на этом этапе я использовал рекомендованную структуру таблицы Dynamodb (с которой я не обязательно согласен, особенно в моем случае использования, но это другая история)
async updateUser(user) {
const now = new Date()
const data = await client.update({
TableName: tableName,
Key: {
pk: `USER#${user.id}`,
sk: `USER#${user.id}`,
},
UpdateExpression:
"set #emailVerified = :emailVerified, #updatedAt = :updatedAt",
ExpressionAttributeNames: {
"#emailVerified": "emailVerified",
"#updatedAt": "updatedAt",
},
ExpressionAttributeValues: {
":emailVerified": user.emailVerified?.toISOString() ?? null,
":updatedAt": now.toISOString(),
},
ReturnValues: "ALL_NEW",
}).promise()
return { ...user, ...data.Attributes }
},
В результате я вижу
user
полностью заселен в
jwt()
Перезвоните:
callbacks: {
async jwt({ token, user, account, profile, isNewUser }) {
console.debug("callback jwt user:", user)
user && (token.user = user)
return token
},
Выходные данные отладки - это полная запись для пользователя из DynamoDB, и ее можно использовать, как описано в ответе @MateuszWawrzynski.