简体   繁体   English

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

[英]aws-amplify-react and nextjs breaks my user context

I cant figure out why but when I use cognito with my own custom user context everything works just fine but as soon as I use withAuthenticator higher order component it breaks my user context and I cant for the life of me figure out why, or even how to fix it.我不知道为什么,但是当我将 cognito 与我自己的自定义用户上下文一起使用时,一切正常,但是一旦我使用 withAuthenticator 高阶组件,它就会破坏我的用户上下文,我终生无法弄清楚为什么,甚至如何要解决这个问题。 Ill post my user context file below for reference and tell you where it breaks.我将在下面发布我的用户上下文文件以供参考,并告诉您它在哪里中断。

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

Under the login function it now returns user not found after I wrap a component and npm i aws-amplify-react .在登录 function 下,它现在返回在我包装组件和npm i aws-amplify-react后未找到的用户。 The funny thing is when I uninstall it I still get the same error and cant go back without fully removing amplify and going through a complete amplify init again.有趣的是,当我卸载它时,我仍然遇到相同的错误,并且在没有完全删除放大并再次完成完整的amplify init的情况下无法返回 go。 Even more confusing, My app is hosted on vercel and that breaks after I attempt to do this on my local machine.更令人困惑的是,我的应用程序托管在 vercel 上,并且在我尝试在本地计算机上执行此操作后中断。 If im not missing something there and my app does break in the cloud even though I dont push my modified code then im guessing cognito is getting something in the cloud when I attempt this on my local machine and then screwing up my untouched copy on vercel?????如果我没有遗漏任何东西并且我的应用程序确实在云中中断,即使我没有推送我修改过的代码,那么我猜测 cognito 在我的本地机器上尝试这个然后在 vercel 上搞砸我未触及的副本时会在云中得到一些东西? ??? Since then Ive also tried using next-auth which makes me think I should just stick to front end work or find a better solution?从那以后,我还尝试使用 next-auth,这让我觉得我应该坚持前端工作还是找到更好的解决方案? any help would be appreciated.任何帮助,将不胜感激。 Ill revert to my old setup and rebuild my cognito and amplify from scratch just to get it going again.生病恢复到我的旧设置并重建我的认知并从头开始放大只是为了让它再次运行。

You need to call Cognito configure prior to calling your auth provider.您需要在调用您的身份验证提供程序之前调用 Cognito 配置。 Place it before you define your auth provider or context.在定义身份验证提供程序或上下文之前放置它。

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

I also use a auth hook with my context that removes the need for a HOC.我还在上下文中使用了身份验证钩子,从而消除了对 HOC 的需求。

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

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

Ensure that your configuration is using all of the proper types.确保您的配置使用所有正确的类型。 If you don't, it sometimes fails silently.如果你不这样做,它有时会默默地失败。 For example ENV files are always passed as strings so some options must be cast to the proper type like cookie expires例如,ENV 文件始终作为字符串传递,因此必须将某些选项转换为正确的类型,例如 cookie expires

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

You will also need to call Auth.configure on every page that you need access to Congito auth inside of getStaticPaths, getStaticProps, and getServerSideProps.您还需要在 getStaticPaths、getStaticProps 和 getServerSideProps 中需要访问 Congito auth 的每个页面上调用 Auth.configure。 This is because they are independently called from your app during build or on a server.这是因为它们是在构建期间或在服务器上从您的应用程序中独立调用的。

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

If you can use it, their hosted UI is pretty good.如果你可以使用它,他们托管的 UI非常好。

Lastly, AWS has a few libraries for Amplify and I use @aws-amplify/auth - I don't know if this makes a difference.最后,AWS 有一些用于 Amplify 的库,我使用@aws-amplify/auth - 我不知道这是否会有所作为。

I added the config file to my _app.js and set ssr: true for ssr authentication我将配置文件添加到我的 _app.js 并设置 ssr: true 用于 ssr 身份验证

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

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

Here is my working user context.这是我的工作用户上下文。 I removed the signup function and will add it later once i work on it and test it.我删除了注册 function 并且稍后会在我处理它并对其进行测试后添加它。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM