Javascript 在React中延迟Auth0重定向,直到收到用户凭据
我正在开发一个用于用户身份验证的React应用程序 目前的进程是:Javascript 在React中延迟Auth0重定向,直到收到用户凭据,javascript,reactjs,asynchronous,oauth,react-router,Javascript,Reactjs,Asynchronous,Oauth,React Router,我正在开发一个用于用户身份验证的React应用程序 目前的进程是: 用户单击主页上的Login按钮,将他们重定向到登录页面,在那里输入登录详细信息并提交表单 提交表单时,用户将使用Auth0登录(或正确处理错误),并重定向回主页 当应用程序刷新时,会调用一个自定义的handleAuthentication()函数,该函数解析URL哈希片段并设置用户会话,其中包括将访问令牌、到期时间和用户信息存储在localStorage中,以在刷新时提供持久性 回到主页后,登录按钮应替换为用户个人资料图像的化身
Login
按钮,将他们重定向到登录页面,在那里输入登录详细信息并提交表单handleAuthentication()
函数,该函数解析URL哈希片段并设置用户会话,其中包括将访问令牌、到期时间和用户信息存储在localStorage
中,以在刷新时提供持久性登录
按钮应替换为用户个人资料图像的化身和他们个人资料页面的链接auth0client.client.userInfo()
的调用是异步的,因此在检索要存储在localStorage
中的用户信息时会有一点延迟。因此,主页很可能在Auth0发送响应之前呈现。当我第二次刷新页面时,用户信息已被检索和存储,因此主页呈现正确
以下是上述流程中的一些相关代码:
auth.login()
auth.handleAuthentication()
auth.setSession()
auth.getUserInfo()
App.js
export default function App() {
auth.handleAuthentication();
return (
<BrowserRouter>
<Suspense fallback={<p>Loading...</p>}>
<Layout>
<Switch>
// Routes to pages
</Switch>
</Layout>
</Suspense>
</BrowserRouter>
导出默认函数App(){
auth.handleAuthentication();
返回(
//到页面的路由
auth
是我创建的一个自定义类,它通过使用localStorage
等扩展默认的Auth0功能
App.js
显示handleAuthentication()
(扩展为,setSession()
)在呈现新路由(本例中为主页)之前被调用。但是setSession()
通常需要比页面呈现时间更长的时间才能完成。因此,当主页加载并调用auth.getUserInfo()时
,用户信息最初可能在localStorage
中丢失,因此用户是未定义的
错误,我大约有一半时间会收到该错误
在做了一些研究之后,我想出了几个可能的解决方案
localStorage
中,并同时显示加载页面。但我在其他答案中读到,您不应延迟呈现,因为这可能会导致其他问题。因此解决方案#2:localStorage
中可用。然后,使用用户信息更新状态,以重新渲染并显示用户的实际化身图像这两种方法中的任何一种都是好的/正确的方法吗?如果不是,还有什么其他方法可以用来解决这个问题?我会这样做: 使用状态跟踪响应何时发生变化
const[arrized,setarrized]=useState(false)
将项目添加到localStorage
后,在setSession()中更改它:
this.auth0Client.client.userInfo(authResult.accessToken, (err, user) => {
if (err) {
console.log("setSession: Couldn't get user info");
return;
} else {
localStorage.setItem("user", JSON.stringify(user));
// over here
setArrived(true);
}
});
并在useffect()中运行getUserInfo()
:
谢谢@Gabriel Lupu,经过一些修改,这个解决方案成功了。我不得不在几个地方添加if(user==undefined)
,这样在useffect
运行之前我就不会出错了。
setSession(authResult) {
// Use the results from handleAuthentication() to set up the user's browser session
let expiresAt = authResult.expiresIn * 1000 + new Date().getTime();
this.accessToken = authResult.accessToken;
this.idToken = authResult.idToken;
this.expiresAt = expiresAt;
localStorage.setItem("access_token", authResult.accessToken);
localStorage.setItem("id_token", authResult.idToken);
localStorage.setItem("expires_at", expiresAt);
this.auth0Client.client.userInfo(authResult.accessToken, (err, user) => {
if (err) {
console.log("setSession: Couldn't get user info");
return;
} else {
localStorage.setItem("user", JSON.stringify(user));
}
});
}
getUserInfo() {
// Return user info
const user = localStorage.getItem("user");
if (!user) {
console.log("getUserInfo: No user info to retrieve");
return;
}
return JSON.parse(user);
}
export default function App() {
auth.handleAuthentication();
return (
<BrowserRouter>
<Suspense fallback={<p>Loading...</p>}>
<Layout>
<Switch>
// Routes to pages
</Switch>
</Layout>
</Suspense>
</BrowserRouter>
this.auth0Client.client.userInfo(authResult.accessToken, (err, user) => {
if (err) {
console.log("setSession: Couldn't get user info");
return;
} else {
localStorage.setItem("user", JSON.stringify(user));
// over here
setArrived(true);
}
});
useEffect(() => {
// run logic here to get the user from localStorage
// I would also keep this information inside state
}, [arrived])