# #reactjs #firebase #firebase-authentication #next.js
Вопрос:
Я уже несколько дней сталкиваюсь с проблемой, и мне не удается ее хорошо решить.
Я использую Firebase
и NextJs
в своем текущем проекте.
Моя текущая цель-войти в систему с пользователем firebase-authentication
.
Однако также должна быть возможность вызывать пользователя в getServerSideProps, а также генерировать idToken в этом.
next-firebase-auth
Упаковка значительно облегчает жизнь. В принципе, пакет позволяет вам делать именно это.
Когда пользователь входит в систему, '/api/login'
вызывается конечная точка для создания маркера обновления и сохранения информации о пользователе, маркера идентификатора и маркера обновления в файлах cookie. Будущие запросы на страницы SSR получают информацию о пользователе и идентификационный токен из файлов cookie, обновляя идентификационный токен по мере необходимости. Теоретически я могу выполнить user.getIdToken() в getServerSideProps.
В репо есть пример сценария, но в котором используется firebaseui-web
. Это позволяет вам выполнить все необходимые настройки. Внутри этого, внутри обратного вызова, signInSuccessWithAuthRes
установлено значение false. И, как я понимаю, ключ здесь, так как только тогда происходит перенаправление туда '/api/login'
, где установлен файл cookie.
Однако я не хочу использовать firebaseui-web
его, так как пользовательский интерфейс выглядит плохо.
Я использую «обычный способ» входа в систему с моим пользователем firebase.auth()
, но меня не перенаправляют '/api/login'
. Я сам пытался проложить маршрут, но всегда получал ошибку
Ошибка: В запросе отсутствует значение заголовка авторизации (я пытался установить Firebase idToken в качестве авторизации на предъявителя, но это не сработало)
Есть ли способ достичь этого без firebaseui-web
этого ?
Мой Подход
./страницы/api/вход в систему
import { setAuthCookies } from 'next-firebase-auth'
import initAuth from '../../initAuth'
initAuth()
const handler = async (req, res) => {
try {
await setAuthCookies(req, res)
} catch (e) {
return res.status(500).json({ error: 'Unexpected error.' })
}
return res.status(200).json({ success: true })
}
export default handler
Part of my loginFuntion
const result = await firebase.auth().signInWithPopup(provider)
const token = await result.user.getIdToken(true)
await axios.post('/api/login', {
headers: {
Authorization: `Bearer ${token}`,
},
})
Example Code from next-firebase-auth GitHub Repo (FirebasAuth.js)
import React, { useEffect, useState } from 'react'
import StyledFirebaseAuth from 'react-firebaseui/StyledFirebaseAuth'
import firebase from 'firebase/app'
import 'firebase/auth'
// Note that next-firebase-auth inits Firebase for us,
// so we don't need to.
const firebaseAuthConfig = {
signInFlow: 'popup',
// Auth providers
// https://github.com/firebase/firebaseui-web#configure-oauth-providers
signInOptions: [
{
provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,
requireDisplayName: false,
},
],
signInSuccessUrl: '/',
credentialHelper: 'none',
callbacks: {
// https://github.com/firebase/firebaseui-web#signinsuccesswithauthresultauthresult-redirecturl
signInSuccessWithAuthResult: () =>
// Don't automatically redirect. We handle redirects using
// `next-firebase-auth`.
**// Thats the Part I am not able to implement in my code !!!**
false,
},
}
const FirebaseAuth = () => {
// Do not SSR FirebaseUI, because it is not supported.
// https://github.com/firebase/firebaseui-web/issues/213
const [renderAuth, setRenderAuth] = useState(false)
useEffect(() => {
if (typeof window !== 'undefined') {
setRenderAuth(true)
}
}, [])
return (
<div>
{renderAuth ? (
<StyledFirebaseAuth
uiConfig={firebaseAuthConfig}
firebaseAuth={firebase.auth()}
/>
) : null}
</div>
)
}
export default FirebaseAuth
initAuth.js (if you need)
import { init } from 'next-firebase-auth'
const TWELVE_DAYS_IN_MS = 12 * 60 * 60 * 24 * 1000
const initAuth = () => {
init({
debug: true,
authPageURL: '/auth',
appPageURL: '/',
loginAPIEndpoint: '/api/login', // required
logoutAPIEndpoint: '/api/logout', // required
// firebaseAuthEmulatorHost: 'localhost:9099',
// Required in most cases.
firebaseAdminInitConfig: {
credential: {
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
// Using JSON to handle newline problems when storing the
// key as a secret in Vercel. See:
// https://github.com/vercel/vercel/issues/749#issuecomment-707515089
privateKey: process.env.FIREBASE_PRIVATE_KEY
? JSON.parse(process.env.FIREBASE_PRIVATE_KEY)
: undefined,
},
databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL,
},
firebaseClientInitConfig: {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
},
cookies: {
name: 'ExampleApp',
keys: [
process.env.NEXT_COOKIE_SECRET_CURRENT,
process.env.NEXT_COOKIE_SECRET_PREVIOUS,
],
httpOnly: true,
maxAge: TWELVE_DAYS_IN_MS,
overwrite: true,
path: '/',
sameSite: 'strict',
secure: process.env.NEXT_PUBLIC_COOKIE_SECURE === 'true',
signed: true,
},
})
}