使用 next auth 时 Firebase 不进行身份验证
Firebase does not authenticate when using next auth
我正在使用带有 firebase 适配器的 next-auth。
在数据库中保存用户方面一切正常,但在身份验证方面有些问题。
import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google"
import { FirebaseAdapter } from "@next-auth/firebase-adapter"
import { db } from "../../../utils/firebase/firebase"
import * as firestoreFunctions from 'firebase/firestore'
import { adminAuth } from "../../../utils/firebase/firebaseAdmin"
import { getAuth, signInWithCustomToken } from "firebase/auth"
const auth = getAuth()
export default NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
state: false,
}),
],
adapter: FirebaseAdapter({
db: db,
...firestoreFunctions,
}),
callbacks: {
async signIn({ user, account, profile, email, credentials }) {
console.log(user, 'user')
const customToken = await adminAuth.createCustomToken(user.id)
const customSignIn = await signInWithCustomToken(auth, customToken)
console.log(customSignIn, 'customSignIn')
console.log(customSignIn.user, 'customSignIn.user')
user = customSignIn.user
console.log(user, 'user 2')
return true
},
async redirect({ url, baseUrl }) {
return baseUrl
},
async session({ session, user, token }) {
if (session?.user) {
session.user.id = token.sub
}
return session
},
async jwt({ token, user, account, profile, isNewUser }) {
if (isNewUser) {
const additionalClaims = {
isStudent: true,
isTeacher: false,
isStaff: false,
isAdmin: false
}
const customToken = await adminAuth.createCustomToken(token.sub, additionalClaims)
const customSignIn = await signInWithCustomToken(auth, customToken)
user = customSignIn.user
}
return token
}
},
session: {
strategy: 'jwt',
},
})
我的用户可以登录,但未通过身份验证。
const auth = getAuth()
onAuthStateChanged(auth, (user) => {
if (user) {
// User is signed in, see docs for a list of available properties
// https://firebase.google.com/docs/reference/js/firebase.User
console.log('user')
console.log(user)
// ...
} else {
console.log('no user')
// User is signed out
// ...
}
})
观察者 returns 'no user',但我已登录。
您没有看到登录用户,因为 firebase 身份验证是在服务器端完成的,而不是客户端。
您应该尝试将 customToken 传递给会话,然后在客户端使用它让用户登录到 firebase 身份验证。
您还希望将 useSession 挂钩包装在如下所示的自定义挂钩中,并使用它代替 useSession。
const useFirebaseSession = () => {
const session = useSession();
const [status, setStatus] = useState(session.status);
useEffect(() => {
if (session && session.status === 'authenticated') {
signInWithCustomToken(auth, session.customToken).then(() => {
setStatus('authenticated');
});
}
}, [session]);
useEffect(() => {
if(session.status !== 'authenticated') {
setStatus(session.status)
}
}, [session.status]);
return { data: session.data, status };
}
好的,所以我最后做的是:
正如@esi 所说,将使用 firebase auth 创建的 customToken 传递给会话:
async jwt({
token,
user,
account,
profile,
isNewUser
}) {
if (isNewUser || user) {
const additionalClaims = {
isStudent: true,
isTeacher: false,
isStaff: false,
isAdmin: false
}
const customToken = await adminAuth.createCustomToken(token.sub, additionalClaims)
console.log(customToken, '***customToken')
token.customToken = customToken
}
return token
}
然后,在会话回调中:
async session({
session,
token,
user
}) {
if (session ? .user) {
session.user.id = token.sub
session.customToken = token.customToken
}
return session
},
最后,在首次重定向用户的页面中:
const [user, setUser] = useState()
useEffect(() => {
if (status === "authenticated") {
const loggedInUser = {
userName: session.user.name,
userEmail: session.user.email,
userPhoto: session.user.image,
userUID: session.user.id,
}
signInWithCustomToken(auth, session.customToken)
dispatch(setActiveUser(loggedInUser))
}
}, [status])
const handleLogOut = () => {
dispatch(setUserLogOutState())
logout()
signOut({
callbackUrl: '/'
}) //TODO: goodbye page
// Rest of jsx code when session is true
就是这样。
希望它也适用于其他人。
谢谢!
我正在使用带有 firebase 适配器的 next-auth。 在数据库中保存用户方面一切正常,但在身份验证方面有些问题。
import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google"
import { FirebaseAdapter } from "@next-auth/firebase-adapter"
import { db } from "../../../utils/firebase/firebase"
import * as firestoreFunctions from 'firebase/firestore'
import { adminAuth } from "../../../utils/firebase/firebaseAdmin"
import { getAuth, signInWithCustomToken } from "firebase/auth"
const auth = getAuth()
export default NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
state: false,
}),
],
adapter: FirebaseAdapter({
db: db,
...firestoreFunctions,
}),
callbacks: {
async signIn({ user, account, profile, email, credentials }) {
console.log(user, 'user')
const customToken = await adminAuth.createCustomToken(user.id)
const customSignIn = await signInWithCustomToken(auth, customToken)
console.log(customSignIn, 'customSignIn')
console.log(customSignIn.user, 'customSignIn.user')
user = customSignIn.user
console.log(user, 'user 2')
return true
},
async redirect({ url, baseUrl }) {
return baseUrl
},
async session({ session, user, token }) {
if (session?.user) {
session.user.id = token.sub
}
return session
},
async jwt({ token, user, account, profile, isNewUser }) {
if (isNewUser) {
const additionalClaims = {
isStudent: true,
isTeacher: false,
isStaff: false,
isAdmin: false
}
const customToken = await adminAuth.createCustomToken(token.sub, additionalClaims)
const customSignIn = await signInWithCustomToken(auth, customToken)
user = customSignIn.user
}
return token
}
},
session: {
strategy: 'jwt',
},
})
我的用户可以登录,但未通过身份验证。
const auth = getAuth()
onAuthStateChanged(auth, (user) => {
if (user) {
// User is signed in, see docs for a list of available properties
// https://firebase.google.com/docs/reference/js/firebase.User
console.log('user')
console.log(user)
// ...
} else {
console.log('no user')
// User is signed out
// ...
}
})
观察者 returns 'no user',但我已登录。
您没有看到登录用户,因为 firebase 身份验证是在服务器端完成的,而不是客户端。
您应该尝试将 customToken 传递给会话,然后在客户端使用它让用户登录到 firebase 身份验证。
您还希望将 useSession 挂钩包装在如下所示的自定义挂钩中,并使用它代替 useSession。
const useFirebaseSession = () => {
const session = useSession();
const [status, setStatus] = useState(session.status);
useEffect(() => {
if (session && session.status === 'authenticated') {
signInWithCustomToken(auth, session.customToken).then(() => {
setStatus('authenticated');
});
}
}, [session]);
useEffect(() => {
if(session.status !== 'authenticated') {
setStatus(session.status)
}
}, [session.status]);
return { data: session.data, status };
}
好的,所以我最后做的是: 正如@esi 所说,将使用 firebase auth 创建的 customToken 传递给会话:
async jwt({
token,
user,
account,
profile,
isNewUser
}) {
if (isNewUser || user) {
const additionalClaims = {
isStudent: true,
isTeacher: false,
isStaff: false,
isAdmin: false
}
const customToken = await adminAuth.createCustomToken(token.sub, additionalClaims)
console.log(customToken, '***customToken')
token.customToken = customToken
}
return token
}
然后,在会话回调中:
async session({
session,
token,
user
}) {
if (session ? .user) {
session.user.id = token.sub
session.customToken = token.customToken
}
return session
},
最后,在首次重定向用户的页面中:
const [user, setUser] = useState()
useEffect(() => {
if (status === "authenticated") {
const loggedInUser = {
userName: session.user.name,
userEmail: session.user.email,
userPhoto: session.user.image,
userUID: session.user.id,
}
signInWithCustomToken(auth, session.customToken)
dispatch(setActiveUser(loggedInUser))
}
}, [status])
const handleLogOut = () => {
dispatch(setUserLogOutState())
logout()
signOut({
callbackUrl: '/'
}) //TODO: goodbye page
// Rest of jsx code when session is true
就是这样。 希望它也适用于其他人。
谢谢!