aws-amplify-react 和 nextjs 破坏了我的用户上下文

aws-amplify-react and nextjs breaks my user context

我不明白为什么,但是当我将 cognito 与我自己的自定义用户上下文一起使用时,一切正常,但是一旦我使用 withAuthenticator 高阶组件,它就会破坏我的用户上下文,我终究无法弄清楚为什么,甚至如何解决它。我会 post 下面我的用户上下文文件以供参考,并告诉你它在哪里中断。

import { Auth } from 'aws-amplify'
import {createContext, useState, useEffect, useMemo} from 'react'

//TODO must redo cognito from scratch and will probably be able to keep this user context untouched

export const UserContext = createContext(null)

export const UserProvider = ({children}) => {
  
  const [ user, setUser ] = useState(null)
  const [ userEmail, setUserEmail ] = useState(null)
  const [ signInError, setSignInError ] = useState(false)

  useEffect(()=>{
    // AWS Cognito
    Auth.currentAuthenticatedUser().then(x=>setUser(x)).catch((err)=>setUser(null))
  },[])

   const handleSignInError = () => {
    console.log(signInError)
  }

  const login = (username, password) => {
    signInError && setSignInError(false)
    Auth.signIn(username, password)
    .then( x => {
      setUser(x)
      console.log('Welcome: ' + x.challengeParam.userAttributes.email)
      setUserEmail(x.challengeParam.userAttributes.email)
      setSignInError(false)
    })
    .catch((err)=>{
      console.log(err.code)
      if(err.code === 'UserNotFoundException' || 'NotAuthorizedException'){
        err.message = 'Invalid username or password'
        setSignInError(true)
        console.log(err.message)
      }
    })  
  }
  
  const logout = () => {
    Auth.signOut().then((x)=>{
      setUser(null)
      setUserEmail(null)
      return x
    })
  }

  const signup = (username, email, password) => {
    Auth.signUp({ username, password, attributes: { email } })
    .then( x => {
      setUser(x)
      return x
    })
    .catch((err)=>{
      if(err.code){
        err.message = 'Your Username or Password was incorrect'
      }
      throw err
    })
  }
  
  const vals = useMemo( () => ({user, login, logout, signup, handleSignInError, userEmail, signInError}), [user, userEmail, signInError])
  
  return(
    <UserContext.Provider value={vals}>
      {children}
    </UserContext.Provider>
  )
}

现在在登录功能下 returns 在我包装组件和 npm i aws-amplify-react 后找不到用户。有趣的是,当我卸载它时,我仍然遇到同样的错误,并且如果不完全删除放大并再次经历完整的 amplify init 就无法返回。更令人困惑的是,我的应用程序托管在 Vercel 上,当我尝试在本地计算机上执行此操作后,它会中断。如果我没有遗漏任何东西并且我的应用程序确实在云中中断,即使我没有推送修改后的代码,那么当我在我的本地机器上尝试这样做然后在 vercel 上搞砸了我未触及的副本时,我猜 cognito 正在云中获取一些东西? ???从那以后我也尝试使用 next-auth 这让我觉得我应该坚持前端工作还是找到更好的解决方案?任何帮助,将不胜感激。我会恢复到我的旧设置并重建我的认知并从头开始放大以使其再次运行。

您需要先调用 Cognito 配置,然后再调用您的身份验证提供商。将它放在定义身份验证提供程序或上下文之前。

Auth.configure({...your_config})
const UserContext = () => {};

我还在我的上下文中使用了 auth hook,这样就不需要 HOC。

import { useContext } from 'react';
export const useAuth = () => useContext(UserContext);

// use it in components and pages
const user = useAuth();

确保您的配置使用了所有正确的类型。如果你不这样做,它有时会默默地失败。例如 ENV 文件总是作为字符串传递,所以一些选项必须转换为正确的类型,如 cookie expires

{
  authenticationFlowType: 'USER_SRP_AUTH',
  cookieStorage: {
    ...other settings
    expires: Number(process.env.NEXT_PUBLIC_COGNITO_COOKIE_EXPIRES),
  }
};

您还需要在需要访问 getStaticPaths、getStaticProps 和 getServerSideProps 内部的 Congito 身份验证的每个页面上调用 Auth.configure。这是因为它们是在构建期间或在服务器上从您的应用程序独立调用的。

Auth.configure({...your_config})
const getStaticProps = () => {};
const getStaticPaths = () => {};
const getServerSideProps = () => {};

能用的话,他们的hosted UI就不错了

最后,AWS 有一些用于 Amplify 的库,我使用 @aws-amplify/auth - 我不知道这是否有影响。

我将配置文件添加到我的 _app.js 并设置 ssr: true 用于 ssr 身份验证

import Amplify from 'aws-amplify'
import config from '../src/aws-exports'

Amplify.configure({...config, ssr: true})

这是我的工作用户上下文。我删除了注册功能,稍后我会在处理和测试后添加它。

import { Auth } from 'aws-amplify'
import {createContext, useState, useEffect, useMemo} from 'react'

export const UserContext = createContext(null)

export const UserProvider = ({children}) => {
  
  const [ user, setUser ] = useState(null)
  const [ userEmail, setUserEmail ] = useState(null)
  const [ signInError, setSignInError ] = useState(false)
  const [sub, setSub] = useState(null)
  useEffect(()=>{
    // AWS Cognito
    Auth.currentAuthenticatedUser()
      .then(x=>{
        setUser(x.username)
        setUserEmail(x.attributes.email)
        setSub(x.attributes.sub)
      })
      .catch((err)=>{
        console.log(err)
        setUser(null)
      })
  },[])

   const handleSignInError = () => {
    console.log(signInError)
  }

  const login = (username, password) => {
    signInError && setSignInError(false);
    Auth.signIn(username, password)
      .then((x) => {
        setUser(x.username)
        setSignInError(false)
        console.log(x)
      })
      .catch((err)=>{
        console.log(err)    
        setSignInError(true)
      })  
  }
  
  const logout = () => {
    Auth.signOut().then((x)=>{
      setUser(null)
      setUserEmail(null)
      setSub(null)
    })
  }

  
  }
  
  const vals = useMemo( () => ({user, sub, login, logout, handleSignInError, userEmail, signInError}), [user, userEmail, signInError, sub])
  
  return(
    <UserContext.Provider value={vals}>
      {children}
    </UserContext.Provider>
  )
}