我正在创建一个React应用-使用create-react-app和amplify-并且我正在尝试设置身份验证。我似乎无法使用托管的UI处理联合登录。
有些页面不需要身份验证即可到达,有些页面则需要用户登录。我想使用托管的UI,因为它是预先构建的。我一直在关注入门文档:https://aws-amplify.github.io/docs/js/authentication
对于背景,我具有以下组件:
-Amplify-一个放大客户端,将调用包装在诸如doSignIn,doSignOut等方法中。该想法是将所有这些代码都放在一个地方。这是一个普通的javascript类
-会话-提供身份验证上下文作为React上下文。使用放大客户端设置此上下文。它具有使用上下文的HOC
-页面-包含在会话HOC withAuthentication
中的页面,仅当用户登录后才呈现页面
此结构实际上来自Firebase教程:https://www.robinwieruch.de/complete-firebase-authentication-react-tutorial/
也许使用Amplify只是不可行?尽管看起来对我来说足够相似,它应该可以工作。基本思想是,会话提供单个身份验证上下文,可以使用withAuthentication
HOC进行订阅。这样,只要用户登录,任何需要用户的组件都将被呈现。
最初,我将整个App组件包装在了文档描述的amplify提供的withAuthenticator
HOC中。但是,这意味着未经身份验证就无法访问任何页面-需要在没有帐户的情况下访问主页。
接下来,我尝试使用登录按钮调用托管UI,然后处理响应。问题在于,托管的UI已经登录了用户,然后将其重定向回应用程序,导致其重新加载-这对于单页应用程序而言并不理想。
然后,我尝试在每次应用启动时检查用户是否已通过身份验证-以处理重定向-但这变得很混乱,因为我需要将许多放大的客户端代码移到Session上下文中以便可以正确初始化。我看到的唯一方法是使用集线器模块:https://aws-amplify.github.io/docs/js/hub#listening-authentication-events的缺点是,登录后,该应用程序将刷新,并且仍有一段时间您注销时,这会使用户体验很奇怪。 >
我本以为会有一种不引起应用程序刷新的方法。也许使用托管UI不可能。对我来说,令人困惑的是文档没有在任何地方提及它。实际上,有关于处理来自托管UI的回调的文档,据我所知,因为整个页面都会刷新,所以回调永远不会运行。
我尝试将其缩小为所需的大小。我可以根据要求提供更多。
放大:
import Amplify, { Auth } from 'aws-amplify';
import awsconfig from '../../aws-exports';
import { AuthUserContext } from '../Session';
class AmplifyClient {
constructor() {
Amplify.configure(awsconfig);
this.authUserChangeListeners = [];
}
authUserChangeHandler(listener) {
this.authUserChangeListeners.push(listener);
}
doSignIn() {
Auth.federatedSignIn()
.then(user => {
this.authUserChangeListeners.forEach(listener => listener(user))
})
}
doSignOut() {
Auth.signOut()
.then(() => {
this.authUserChangeListeners.forEach(listener => listener(null))
});
}
}
const withAmplify = Component => props => (
<AmplifyContext.Consumer>
{amplifyClient => <Component {...props} amplifyClient={amplifyClient} />}
</AmplifyContext.Consumer>
);
会话:
const provideAuthentication = Component => {
class WithAuthentication extends React.Component {
constructor(props) {
super(props);
this.state = {
authUser: null,
};
}
componentDidMount() {
this.props.amplifyClient.authUserChangeHandler((user) => {
this.setState({authUser: user});
});
}
render() {
return (
<AuthUserContext.Provider value={this.state.authUser}>
<Component {...this.props} />
</AuthUserContext.Provider>
);
}
}
return withAmplify(WithAuthentication);
};
const withAuthentication = Component => {
class WithAuthentication extends React.Component {
render() {
return (
<AuthUserContext.Consumer>
{user =>
!!user ? <Component {...this.props} /> : <h2>You must log in</h2>
}
</AuthUserContext.Consumer>
);
}
}
return withAmplify(WithAuthentication);
};
最高一次提供auth上下文:
export default provideAuthentication(App);
然后需要身份验证的页面可以使用它:
export default withAuthentication(MyPage);
我想发生的是,在用户登录之后,我可以设置AuthUserContext,依次更新所有侦听器。但是由于重定向导致整个应用刷新Auth.federatedSignIn()
中的承诺,因此无法解决。即使他们确实这样做,这也会导致向用户显示You must log in
。
有没有办法在仍然使用托管UI的情况下阻止此重定向?也许在另一个选项卡或没有关闭我的应用程序的弹出窗口中启动它?还是我走错路了?只是感觉不太“反应”而导致整页刷新。
任何帮助将不胜感激。我可以根据要求提供更多详细信息。
答案 0 :(得分:0)
您可以使用Amplify的内置消息传递系统来侦听事件,而不必链接到Auth
的承诺。这是我在自定义钩子中的操作方式以及如何处理Redux中呈现的内容。
import { Auth, Hub } from 'aws-amplify';
import { useEffect } from 'react';
function useAuth({ setUser, clearUser, fetchQuestions, stopLoading }) {
useEffect(() => {
Hub.listen('auth', ({ payload: { event, data } }) => {
if (event === 'signIn') {
setUser(data);
fetchQuestions();
stopLoading();
}
if (event === 'signOut') {
clearUser();
stopLoading();
}
});
checkUser({ fetchQuestions, setUser, stopLoading });
}, [clearUser, fetchQuestions, setUser, stopLoading]);
}
async function checkUser({ fetchQuestions, setUser, stopLoading }) {
try {
const user = await Auth.currentAuthenticatedUser();
setUser(user);
fetchQuestions();
} catch (error) {
console.log(error);
} finally {
stopLoading();
}
}