【问题标题】:React Hooks Auth0-js Context Hook Not UpdatingReact Hooks Auth0-js 上下文挂钩未更新
【发布时间】:2019-07-19 17:41:53
【问题描述】:

无论出于何种原因,有时用户在通过身份验证时会得到更新,有时则不会。也许这是我的连接速度的问题,但我不明白为什么当我登录用户时我需要刷新页面以使用户出现。我认为我错误地使用了钩子,因此感谢所有帮助。如何让用户在登录/注册时实时更新,而不是刷新页面。

这是我的授权文件:

import auth0 from 'auth0-js';
import history from '../history';
import config from "../config/auth_config.js";

export default class Auth {

  accessToken;
  idToken;
  expiresAt;

  auth0 = new auth0.WebAuth({
    domain: config.domain,
    clientID: config.clientId,
    redirectUri: `${window.location.origin}/auth0_callback`,
    responseType: 'token id_token',
    scope: 'openid profile email',
  })

  // login method takes email password and db connection
  login = (email, password) => {
    this.auth0.authorize({
      "connection": 'Username-Password-Authentication',
      "email": email,
      "password": password,
    }, function (err) {
      console.log(err);
      if (err) return alert('Something went wrong: ' + err);
    })
  }

  // signup method takes email password and db connection
  signUp = (email, password) => {
    this.auth0.redirect.signupAndLogin({
      "connection": 'Username-Password-Authentication',
      "email": email,
      "password": password
    }, function (err) {
      if (err) return alert('Something went wrong: ' + err);
    })
  };

  // logoout method removes all id's from local storage
  logout = () => {
    localStorage.removeItem('access_token')
    localStorage.removeItem('id_token')
    localStorage.removeItem('expires_at')
    localStorage.removeItem('user')
    history.replace('/');
  }

  // method called once callback initiated
  handleAuthentication = () => {
    if (typeof window !== 'undefined') {
      this.auth0.parseHash((err, authResult) => {
        debugger;
        if (authResult && authResult.accessToken && authResult.idToken) {
          this.setSession(authResult);
        } else if (err) {
          console.log(err)
          return err;
        }
      })
    }
  }


  isAuthenticated = () => {
    if (typeof localStorage !== 'undefined') {
      const expiresAt = JSON.parse(localStorage.getItem('expires_at'))
      return new Date().getTime() < expiresAt
    } else {
      return false
    }
  }

  setSession = authResult => {
    const expiresAt = JSON.stringify(
      authResult.expiresIn * 1000 + new Date().getTime()
    )
    localStorage.setItem('access_token', authResult.accessToken)
    localStorage.setItem('id_token', authResult.idToken)
    localStorage.setItem('expires_at', expiresAt)

    this.auth0.client.userInfo(authResult.accessToken, (err, user) => {
      localStorage.setItem('user', JSON.stringify(user))
    })

    history.replace('/');
  }

  renewSession = () => {
    this.auth0.checkSession({}, (err, authResult) => {
      if (authResult && authResult.accessToken && authResult.idToken) {
        this.setSession(authResult);
      } else if (err) {
        this.logout();
        console.log(err);
        alert(
          `Could not get a new token (${err.error}: ${err.error_description}).`
        );
      }
    });
  }

  getUser = () => {
    if (localStorage.getItem('user')) {
      return JSON.parse(localStorage.getItem('user'))
    }
  }

  getUserName = () => {
    if (this.getUser()) {
      return this.getUser().name
    }
  }

  getToken = () => {
    return localStorage.getItem('id_token')
  }
}

我的应用文件:

import React, { useContext, useEffect } from "react";
import './App.scss';

import { Router, Route, Switch } from "react-router-dom";
import history from "./history";
import Auth from "./auth/Auth";
import Home from "./scenes/Home/Home";
import SignUp from "./scenes/SignUp/SignUp";
import Auth0Callback from "./scenes/Auth0Callback/Auth0Callback";


export const Auth0Context = React.createContext();
export const useAuth0 = () => useContext(Auth0Context);

const auth = new Auth();
let authenticated = auth.isAuthenticated();
let user = auth.getUser();

const handleAuthentication = (nextState, replace) => {
  console.log(nextState);
  if (/access_token|id_token|error/.test(nextState.location.hash)) {
    auth.handleAuthentication();
    authenticated = auth.isAuthenticated();
    user = auth.getUser();
  }
}

function App() {

  // here is where I get false the first time until i hard refresh
  console.log(authenticated);  
  // I get undefined until I hard refresh
  console.log(user);

  // call as if componentDidMount to see if user is logged in
  // if so extend their session
  useEffect(() => {
    if (localStorage.getItem("isLoggedIn") === "true") {
      auth.renewSession();
    }
  }, []);


  return (
    <Auth0Context.Provider value={{ authenticated, user }}>
      <div className="App">
        <Router history={history}>
          <Switch>
            <Route path="/" exact component={Home} />
            <Route path="/signup" exact component={SignUp} />
            <Route path="/auth0_callback" render={(props) => {
              handleAuthentication(props);
              return <Auth0Callback {...props} />
            }} />
          </Switch>
        </Router>
      </div>
    </Auth0Context.Provider>
  );
}

export default App;

回调页面:

import React from 'react'
import { ClipLoader } from 'react-spinners'

import Auth from '../../auth/Auth'

const Auth0CallbackPage = () => {
  return (
    <div>
      <h1>
        This is the auth callback page
      </h1>
      <ClipLoader sizeUnit="px" size={150} />
    </div>
  )
}

export default Auth0CallbackPage

【问题讨论】:

    标签: reactjs auth0 react-hooks react-context


    【解决方案1】:

    对于这样的安葬问题,第一步是确保您的道具按照您的预期进行渲染。另一种选择是在按照您的工作流程进行时捕获 HAR 文件,以验证所有内容都按照您的预期向下传播。虽然这不能解决您的问题,但它可能对您的探索有所帮助。

    https://auth0.com/docs/troubleshoot/har

    【讨论】:

    • 谢谢,帮了大忙。我通常没有设置保留日志,以便帮助查看问题。第一次收到用户信息请求时,我得到的响应是“OK”,当我刷新页面时,我实际上收到了一个显示所有用户信息的新调用。这似乎是一个选项与获取请求。想知道如何解决这个问题
    • 它不再这样做了,所以可能是一个案例。使用 auth0 api 时,我总是遇到很多奇怪的问题。昨天我不断收到问题说我没有“连接”:“用户名-密码-身份验证”,即使我从未从我的代码中删除它。今天,这个错误不存在了。我很肯定我的主要问题在于我如何使用钩子。
    【解决方案2】:

    我花了几天时间才弄明白,但感谢莫里森为我指明了正确的方向。问题在于钩子没有更新,因为我只是将值传递给上下文而不是动态值。这就是为什么我刷新时它会更新。

    关键是将 Auth0Context.Provider 从 App.js 内部移动到它自己的文件中,该文件还包含所有其他功能以及用户和已验证的实际状态。希望这可以帮助其他人,但基本上对于钩子,我需要确保上下文在钩子内发生变化。

     import React, {useContext, useState} from 'react'
        import auth0 from 'auth0-js';
        import history from '../history';
        import config from "../config/auth_config.js";
    
        export const Auth0Context = React.createContext();
        export const useAuth0 = () => useContext(Auth0Context);
    
        const Auth0Provider = (props) => {
    
          const [authenticated, setAuthenticated] = useState();
          const [user, setUser] = useState();
    
          const auth0Client = new auth0.WebAuth({
            domain: config.domain,
            clientID: config.clientId,
            redirectUri: `${window.location.origin}/auth0_callback`,
            responseType: 'token id_token',
            scope: 'openid profile email',
          })
    
          // login method takes email password and db connection
          const login = (email, password) => {
            auth0Client.authorize({
              "connection": 'Username-Password-Authentication',
              "email": email,
              "password": password,
            }, function (err) {
              console.log(err);
              if (err) return alert('Something went wrong: ' + err);
            })
          }
    
          // signup method takes email password and db connection
          const signUp = (email, password) => {
            auth0Client.redirect.signupAndLogin({
              "connection": 'Username-Password-Authentication',
              "email": email,
              "password": password
            }, function (err) {
              if (err) return alert('Something went wrong: ' + err);
            })
          };
    
          // logoout method removes all id's from local storage
          const logout = () => {
            localStorage.removeItem('access_token')
            localStorage.removeItem('id_token')
            localStorage.removeItem('expires_at')
            localStorage.removeItem('user')
            history.replace('/');
            setAuthenticated(false);
            setUser(null);
          }
    
          // method called once callback initiated
          const handleAuthentication = () => {
            if (typeof window !== 'undefined') {
              auth0Client.parseHash((err, authResult) => {
                if (authResult && authResult.accessToken && authResult.idToken) {
                  setSession(authResult);
                } else if (err) {
                  console.log(err)
                  return err;
                }
              })
            }
          }
    
    
    
          const isAuthenticated = () => {
            if (typeof localStorage !== 'undefined') {
              const expiresAt = JSON.parse(localStorage.getItem('expires_at'))
              setAuthenticated(true);
              return new Date().getTime() < expiresAt
            } else {
              return false
            }
          }
    
          const setSession = async authResult => {
            console.log(authResult);
            const expiresAt = JSON.stringify(
              authResult.expiresIn * 1000 + new Date().getTime()
            )
            localStorage.setItem('access_token', authResult.accessToken)
            localStorage.setItem('id_token', authResult.idToken)
            localStorage.setItem('expires_at', expiresAt)
    
            localStorage.setItem('user', authResult.idTokenPayload)
            setAuthenticated(true);
            setUser(authResult.idTokenPayload);
    
            history.replace('/');
          }
    
          const renewSession = () => {
            auth0Client.checkSession({}, (err, authResult) => {
              if (authResult && authResult.accessToken && authResult.idToken) {
                this.setSession(authResult);
              } else if (err) {
                this.logout();
                console.log(err);
                alert(
                  `Could not get a new token (${err.error}: ${err.error_description}).`
                );
              }
            });
          }
    
          const getUser = () => {
            if (localStorage.getItem('user')) {
              return JSON.parse(localStorage.getItem('user'))
            }
          }
    
          const getUserName = () => {
            if (this.getUser()) {
              return this.getUser().name
            }
          }
    
          const getToken = () => {
            return localStorage.getItem('id_token')
          }
    
          return (
            <Auth0Context.Provider
              value={{
                login,
                signUp,
                logout,
                handleAuthentication,
                isAuthenticated,
                setSession,
                renewSession,
                getUser,
                getUserName,
                getToken,
                authenticated,
                user
              }}
            >
              {props.children}
            </Auth0Context.Provider>
          );
        }
    
        export default Auth0Provider;
    

    新的 app.js 文件:

    import Auth0Callback from "./scenes/Auth0Callback/Auth0Callback";
    import { useAuth0 } from "./auth/Auth";
    
    function App() {
    
      const { renewSession, handleAuthentication } = useAuth0();
    
      const handleAuth = (nextState, replace) => {
        if (/access_token|id_token|error/.test(nextState.location.hash)) {
          handleAuthentication();
        }
      }
      // call as if componentDidMount to see if user is logged in
      // if so extend their session
      useEffect(() => {
        if (localStorage.getItem("isLoggedIn") === "true") {
          renewSession();
        }
      }, []);
    
    
      return (
        <div className="App">
          <Router history={history}>
            <Switch>
              <Route path="/" exact component={Home} />
              <Route path="/signup" exact component={SignUp} />
              <Route path="/login" exact component={Login} />
              <Route path="/auth0_callback" render={(props) => {
                handleAuth(props);
                return <Auth0Callback {...props} />
              }} />
            </Switch>
          </Router>
        </div>
      );
    }
    
    export default App;
    

    【讨论】:

      猜你喜欢
      • 2021-12-19
      • 2023-03-06
      • 2021-03-22
      • 2020-01-16
      • 2022-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-08
      相关资源
      最近更新 更多