Обработка обратного вызова firebase-аутентификации без firebaseui-web (далее-firebase-аутентификация)

# #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,
    },
  })
}