属性更新后更新用户上下文 - AWS Amplify
Posted
技术标签:
【中文标题】属性更新后更新用户上下文 - AWS Amplify【英文标题】:Update User Context After Attribute Update - AWS Amplify 【发布时间】:2019-12-16 04:00:26 【问题描述】:我有一个要求,即首次用户在登录后会看到一个他们需要同意的弹出窗口。我在 Cognito 中创建了一个自定义属性,该属性标记为“是”,直到用户单击同意按钮。所有这些逻辑都有效,除非您刷新页面时再次向用户显示弹出窗口,尽管同意并且在 Cognito 中更改了属性。
我正在使用带有 useContext 钩子的 React 上下文 API。我在 React 工具中注意到上下文没有更新,这可能是问题所在。
AuthContext.js
import React from 'react';
export const AuthContext = React.createContext();
export const AuthProvider = AuthContext.Provider;
App.js
import React from 'react';
import withRouter from 'react-router-dom';
import Header from './components/Header';
import Routes from './Routes';
import useAmplifyAuth from './libs/useAmplifyAuth';
import AuthProvider from './context/AuthContext';
import InitialLoginModal from './components/InitialLoginModal';
function App()
const
state: user ,
handleSignout
= useAmplifyAuth();
return (
<>
<AuthProvider value= user, handleSignout >
<>
<Header />
<Routes />
<InitialLoginModal />
</>
</AuthProvider>
</>
);
export default withRouter(App);
InitialLoginModal.js
import React, useContext, useState, useEffect from 'react';
import Modal, Button, Image from 'react-bootstrap';
import Auth from 'aws-amplify';
import imgLogo from '../img/logo.jpg';
import AuthContext from '../context/AuthContext';
const InitialLoginModal = () =>
const user, handleSignout = useContext(AuthContext);
const [showModal, setShowModal] = useState(false);
const [initialLogin, setInitialLogin] = useState('');
const noAccept = () =>
setShowModal(false);
handleSignout();
;
useEffect(() =>
if (user)
console.log(user.attributes['custom:initiallogin']);
if (user.attributes['custom:initiallogin'] === 'Yes')
setShowModal(true);
, [user]);
const accept = () =>
updateInitialLogin();
setShowModal(false);
;
const updateInitialLogin = async () =>
await Auth.updateUserAttributes(user, 'custom:initiallogin': 'No' );
setInitialLogin('No');
setShowModal(false);
;
return (
<>
/* Initial login modal */
<Modal
show=showModal
onHide=noAccept
dialogClassName="modal-70w modal-item"
aria-labelledby="Initial Login Modal"
>
<Modal.Header closeButton>
<Modal.Title>
<Image
src=imgLogo
fluid
className="modal-image-center"
/>
</Modal.Title>
</Modal.Header>
<Modal.Body>
<p>
Text that I must agree to.
</p>
</Modal.Body>
<Modal.Footer>
<Button onClick=accept>Next</Button>
</Modal.Footer>
</Modal>
</>
);
;
export default InitialLoginModal;
使用AmplifyAuth.js
import useReducer, useState, useEffect from 'react';
import Auth, Hub from 'aws-amplify';
const amplifyAuthReducer = (state, action) =>
switch (action.type)
case 'FETCH_USER_DATA_INIT':
return
...state,
isLoading: true,
isError: false
;
case 'FETCH_USER_DATA_SUCCESS':
return
...state,
isLoading: false,
isError: false,
user: action.payload.user
;
case 'FETCH_USER_DATA_FAILURE':
return ...state, isLoading: false, isError: true ;
case 'RESET_USER_DATA':
return ...state, user: null ;
default:
throw new Error();
;
const useAmplifyAuth = () =>
const initialState =
isLoading: true,
isError: false,
user: null
;
const [state, dispatch] = useReducer(amplifyAuthReducer, initialState);
const [triggerFetch, setTriggerFetch] = useState(false);
useEffect(() =>
let isMounted = true;
const fetchUserData = async () =>
if (isMounted)
dispatch( type: 'FETCH_USER_DATA_INIT' );
try
if (isMounted)
const data = await Auth.currentAuthenticatedUser();
if (data)
dispatch(
type: 'FETCH_USER_DATA_SUCCESS',
payload: user: data
);
catch (error)
if (isMounted)
dispatch( type: 'FETCH_USER_DATA_FAILURE' );
;
const HubListener = () =>
Hub.listen('auth', data =>
const payload = data;
onAuthEvent(payload);
);
;
const onAuthEvent = payload =>
switch (payload.event)
case 'signIn':
if (isMounted)
setTriggerFetch(true);
console.log('signed in');
break;
default:
return;
;
HubListener();
fetchUserData();
return () =>
Hub.remove('auth');
isMounted = false;
;
, [triggerFetch]);
const handleSignout = async () =>
try
console.log('signed out');
await Auth.signOut();
setTriggerFetch(false);
dispatch( type: 'RESET_USER_DATA' );
catch (error)
console.error('Error signing out user ', error);
;
return state, handleSignout ;
;
export default useAmplifyAuth;
最后,我只需要用户能够同意这些条款,更新他们的自定义属性,之后不再显示模态框。任何帮助,将不胜感激。谢谢。
@vencovsky 建议后的新 InitialLoginModal.jsimport React, useContext, useEffect, useState from 'react';
import Modal, Button, Image from 'react-bootstrap';
import Auth from 'aws-amplify';
import imgLogo from '../img/logo.jpg';
import AuthContext from '../context/AuthContext';
const InitialLoginModal = () =>
const
user,
handleSignout,
shouldShowModal,
setShouldShowModal
= useContext(AuthContext);
const [showModal, setShowModal] = useState(shouldShowModal);
// const [initialLogin, setInitialLogin] = useState('');
const noAccept = () =>
setShowModal(false);
handleSignout();
;
useEffect(() =>
if (user)
if (user.attributes['custom:initiallogin'] === 'Yes')
setShowModal(true);
, [user, setShouldShowModal]);
const accept = () =>
updateInitialLogin();
// setShouldShowModal(false);
;
const updateInitialLogin = async () =>
if (user)
await Auth.updateUserAttributes(user, 'custom:initiallogin': 'No' );
setShowModal(false);
;
return (
<>
/* Initial login modal */
<Modal
show=showModal
onHide=noAccept
dialogClassName="modal-70w modal-item"
aria-labelledby="Initial Login Modal"
>
<Modal.Header closeButton>
<Modal.Title>
<Image
src=imgLogo
fluid
className="modal-image-center"
/>
</Modal.Title>
</Modal.Header>
<Modal.Body>
<p>
Info here
</p>
</Modal.Body>
<Modal.Footer>
<Button onClick=accept>Next</Button>
</Modal.Footer>
</Modal>
</>
);
;
export default InitialLoginModal;
【问题讨论】:
useAmplifyAuth
中有什么内容?
useAmplifyAuth 是用于放大身份验证的自定义挂钩。我会将它的代码添加到帖子中。
【参考方案1】:
我自己也遇到了这个问题,我相信这是需要更新的行:
const data = await Auth.currentAuthenticatedUser();
到:
const data = await Auth.currentAuthenticatedUser(bypassCache: true);
这将直接从 Cognito 检索更新的属性,以便当属性设置为 custom:initiallogin = 'No' 时不会向用户显示模式。
【讨论】:
【参考方案2】:不确定这是否正确,但您的上下文中应该有一个状态来决定它是否应该显示模态。
function App()
const [shouldShowModal, setShouldShowModal] = useState(true) // you can choose if you want true or false
const
state: user ,
handleSignout
= useAmplifyAuth();
return (
<>
<AuthProvider value= user, handleSignout, shouldShowModal, setShouldShowModal >
<>
<Header />
<Routes />
<InitialLoginModal />
</>
</AuthProvider>
</>
);
showModal
的默认值应该来自上下文。
const InitialLoginModal = () =>
const user, handleSignout, shouldShowModal, setShouldShowModal = useContext(AuthContext);
const [showModal, setShowModal] = useState(shouldShowModal );
...
然后您可以使用setShouldShowModal
做更多的事情,因此当您获得身份验证时,您可以选择是否显示。
【讨论】:
谢谢@vencovsky。对于其他功能,我使用的是 setShowModal 还是 setShouldShowModal?我已经尝试了这两种方法并将它们混合在一起,但还没有找到让它工作的方法。For the other functions
是什么意思?
InitialLoginModal 中更新模态状态的函数。
您可以将setShowModal
替换为setShouldShowModal
。只需在上下文中使用一个,然后您就可以挂载和卸载组件,并且状态仍然存在
我在上面的代码中添加了新的 InitialLoginModal.js,因为它不适合这里。就目前而言,尽管发生了变化,但在刷新页面后仍会出现模式。谢谢!【参考方案3】:
在 cognito AWS 界面中为需要访问数据的应用客户端选择“oauth scopes”下的“profile”。
【讨论】:
以上是关于属性更新后更新用户上下文 - AWS Amplify的主要内容,如果未能解决你的问题,请参考以下文章
为啥有些用户在 AWS ElasticBeanstalk 中部署后没有体验到更新?
带有 Cognito 的 AWS Lambda API 网关 - 如何使用 IdentityId 访问和更新 UserPool 属性?
使用 Expo 更新 APNS 证书后出现 AWS Pinpoint 错误