如何在React SPA的浏览器中保留Auth0登录状态 [英] How to persist Auth0 login status in browser for React SPA

查看:141
本文介绍了如何在React SPA的浏览器中保留Auth0登录状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当前,当我创建路由时,我会检查Auth0方法-isAuthenticated()-确定是否返回受保护的页面或重定向至登录.但是,此状态仅存在于内存中,不会在刷新浏览器时将用户保留在其页面上,我想这样做.

Currently when I create my routes, I check an Auth0 method - isAuthenticated() - to determine whether or not to return a protected page or redirect to login. However, this state only exists in memory and does not keep a user on their page upon browser refresh and I would like to do so.

这是一个React/RR4/React Context应用程序,我的Auth0方法列在Auth.js中(如下).

This is a React/RR4/React Context app and my Auth0 methods are listed in Auth.js (below).

强烈建议将登录状态存储在localStorage中.而且,如果我将Auth0令牌存储在cookie中,由于没有设置服务器验证,因此我不确定如何验证令牌.什么条件可以检查以确保安全的数据持久性?

It is highly inadvisable to store login state in localStorage. And if I store my Auth0 tokens in cookies, I'm not sure how I would validate the tokens since there is no server validation set up. What is the correct condition to check that will enable secure data persistence?

ProtectedRoutes.jsx:

ProtectedRoutes.jsx:

   <Route
      exact
      key={route.path}
      path={route.path}
      render={() => (
        // CONDITION TO CHECK
        context.auth.isAuthenticated()
          ? (
            <div>
              <route.component />
            </div>
          ) : <Redirect to="/login" />
        )}
      />

Auth.js(已添加供参考):

Auth.js (added for reference):

import auth0 from 'auth0-js';
import authConfig from './auth0-variables';

class Auth {
  accessToken;
  idToken;
  expiresAt;
  tokenRenewalTimeout;

  auth0 = new auth0.WebAuth({
    domain: authConfig.domain,
    clientID: authConfig.clientId,
    redirectUri: authConfig.callbackUrl,
    responseType: 'token id_token',
    scope: 'openid'
  });

  constructor() {
    this.scheduleRenewal();
    this.login = this.login.bind(this);
    this.logout = this.logout.bind(this);
    this.handleAuthentication = this.handleAuthentication.bind(this);
    this.isAuthenticated = this.isAuthenticated.bind(this);
    this.getAccessToken = this.getAccessToken.bind(this);
    this.getIdToken = this.getIdToken.bind(this);
    this.renewSession = this.renewSession.bind(this);
    this.scheduleRenewal = this.scheduleRenewal.bind(this);
  }

  login() {
    console.log('logging in!');
    this.auth0.authorize();
  }

  handleAuthentication() {
    return new Promise((resolve, reject) => {
      this.auth0.parseHash((err, authResult) => {
        if (err) return reject(err);
        console.log(authResult);
        if (!authResult || !authResult.idToken) {
          return reject(err);
        }
        this.setSession(authResult);
        resolve();
      });
    });
  }

  getAccessToken() {
    return this.accessToken;
  }

  getIdToken() {
    return this.idToken;
  }

  getExpiration() {
    return new Date(this.expiresAt);
  }

  isAuthenticated() {
    let expiresAt = this.expiresAt;
    return new Date().getTime() < expiresAt;
  }

  setSession(authResult) {
    localStorage.setItem('isLoggedIn', 'true');
    let expiresAt = (authResult.expiresIn * 1000) + new Date().getTime();
    this.accessToken = authResult.accessToken;
    this.idToken = authResult.idToken;
    this.expiresAt = expiresAt;
    this.scheduleRenewal();
  }

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

  scheduleRenewal() {
    let expiresAt = this.expiresAt;
    const timeout = expiresAt - Date.now();
    if (timeout > 0) {
      this.tokenRenewalTimeout = setTimeout(() => {
        this.renewSession();
      }, timeout);
    }
  }

  logout() {
    this.accessToken = null;
    this.idToken = null;
    this.expiresAt = 0;
    localStorage.removeItem('isLoggedIn');
    clearTimeout(this.tokenRenewalTimeout);
    console.log('logged out!');
  }
}

export default Auth;

推荐答案

您可以使用静默身份验证,以在刷新浏览器时更新令牌.

You can use Silent authentication to renew the tokens on browser refresh.

专门针对您的React SPA应用

Specifically for your react SPA app

  • 在主要App组件中将状态tokenRenewed设置为false
  • 您在auth.js中已经有一个renewToken方法,因此请在componentDidMount方法中调用它
  • setup a state say tokenRenewed to false in your main App component
  • you already have a renewToken method in your auth.js so call that in componentDidMount method
componentDidMount() {
   this.auth.renewToken(() => {
      this.setState({tokenRenewed : true});
   })
}

  • 更新renewToken以接受如下所示的回调cb
    • update renewToken to accept a callback cb like below
    • renewSession(cb) {
          this.auth0.checkSession({}, (err, authResult) => {
            if (authResult && authResult.accessToken && authResult.idToken) {
              this.setSession(authResult);
            } else if (err) {
              this.logout();
              console.log(`Could not get a new token. (${err.error}: ${err.error_description})`);
            }
            if(cb) cb(err, authResult);
          });
        }
      

      • 确保除非tokenRenewedtrue,即除非您具有通过静默身份验证更新的有效令牌,否则不要加载App组件.
        • Make sure you don't load the App component unless tokenRenewed is true i.e. unless you have the valid tokens renewed via silent authentication
        • render() {
              if(!this.state.tokenRenewed) return "loading...";
              return (
                // Your App component
              );
          }
          

          注释:

          1. 您可能需要确保在应用程序"设置中设置了正确的Allowed Web Origins才能正常工作
          2. 静默身份验证存在一些局限性,因为它要求在浏览器上启用第三者Cookie,并在Safari使用ITP的情况下.您应该设置一个自定义域来避免这种情况.请参阅官方auth0文档以在此处了解更多信息.
          3. 有关如何安全存储令牌的更多详细信息此处
          1. You may want to make sure you have the correct Allowed Web Origins set in the Application settings for this to work
          2. Silent authentication has some limitations as in it requires 3rd party cookies enabled on the browser and in case ITP for Safari. You should setup a custom domain to avoid that. Refer to the official auth0 docs to learn more here.
          3. More details on how to store token securely here

          这篇关于如何在React SPA的浏览器中保留Auth0登录状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆