Проблемы с перенаправлением после успешной попытки входа в систему Auth0

Используя react-router и responses context API, я пытаюсь аутентифицировать пользователя в Auth0, а затем перенаправлять пользователя на домашнюю страницу при успешном входе в систему. Что мне не хватает в маршрутизации? Я передаю контекст остальной части приложения, обертывая приложение, используя и передавая методы входа и выхода вниз по дереву. Когда я вызываю метод login() из дочернего компонента, вызывается метод входа в контекст, где я устанавливаю для состояния {isAuthenticated} значение true, а затем я вызываю Auth.login() из компонента контекста, как показано в прикрепленном коде. .

Я просмотрел документы Auth0 и настроил правильный маршрут обратного вызова для http://локальный:3000/админ/панель управления.

Когда я нажимаю «Войти» на странице, в первый раз появляется соответствующий компонент Auth0, и я могу войти в систему, однако после того, как я ввожу учетные данные и нажимаю кнопку входа, я перенаправляюсь обратно к компоненту {Login}. Если после этого я снова нажму кнопку входа в компоненте {Login}, я увижу, что страница пытается перенаправить на мой домашний маршрут, а затем она вернет меня обратно к компоненту {Login}.

import auth from '../Auth/Auth'

const AuthContext = React.createContext();
const Auth = new auth();

class AuthProvider extends React.Component {
  state = { isAuthenticated: false }
  constructor() {
    super()
    this.login = this.login.bind(this)
    this.logout = this.logout.bind(this)
  }

  auth0Signin() {
    Auth.login()
  } 

  login() {
    this.setState({ isAuthenticated: true })
    this.auth0Signin()
  }

  logout() {
    Auth.logout()
    this.setState({ isAuthenticated: false })
  }

  render() {
    return (
      <AuthContext.Provider
        value = {{
          isAuthenticated: this.state.isAuthenticated,
          login: this.login,
          logout: this.logout
        }}
      >
        {this.props.children}
      </AuthContext.Provider>
    )
  }
}
const AuthConsumer = AuthContext.Consumer

export { AuthProvider, AuthConsumer };


import Auth from './Auth/Auth'
import Callback from './views/components/Callback'
import { createBrowserHistory } from "history";
import React from 'react';
import "react-notification-alert/dist/animate.css";
import { Redirect, Route, Router, Switch } from "react-router-dom";
import { AuthConsumer, AuthProvider } from './providers/AuthContext';
import Login from './views/pages/Login';
import Register from './views/pages/Register'
import Dashboard from './layouts/Admin/Admin'

const auth = new Auth()
const hist = createBrowserHistory();

const handleAuthentication = (nextState, replace) => {
  if (/access_token|id_token|error/.test(nextState.location.hash)) {
    auth.handleAuthentication();
  }
}

const ProtectedRoute = ({ component: Component, ...rest }) => (
  <AuthConsumer>
    {({ isAuthenticated, login, logout}) => (
      <Route
        render = {props =>
          isAuthenticated ? <Component login = {login} logout = {logout} isAuthenticated = {isAuthenticated} {...props} /> : <Redirect to='/auth/login' />}
        {...rest}
      />
    )}
  </AuthConsumer>
)

const PublicRoute = ({ component: Component, ...rest }) => (
  <AuthConsumer>
    {({ isAuthenticated, login, logout}) => (
      <Route
        render = {props =><Component login = {login} logout = {logout} isAuthenticated = {isAuthenticated} {...props} /> }
        {...rest}
      />
    )}
  </AuthConsumer>
)

const App = () => {
  return (
    <>
      <Router history = {hist}>
        <AuthProvider>
          {/* <Header /> */}
            <Switch>
              <ProtectedRoute path='/admin/dashboard' component = {Dashboard} />
              <PublicRoute path='/auth/Register' component = {Register} />
              <PublicRoute path='/auth/Login' component = {Login} />
              <Route path = "/callback" render = {(props) => {
                  handleAuthentication(props);
                  return <Callback {...props} /> 
                }}/>
              <PublicRoute path='/' component = {Login} />
            </Switch>
          {/* <Footer /> */}
        </AuthProvider>
      </Router>
    </>
  );
}

export default App;



import auth0 from 'auth0-js';
import { AUTH_CONFIG } from './auth0-variables';
import history from './History';

export default class Auth {
  auth0 = new auth0.WebAuth({
    domain: AUTH_CONFIG.domain,
    callbackUrl: AUTH_CONFIG.callbackUrl,
    clientID: AUTH_CONFIG.clientId,
    redirectUri: AUTH_CONFIG.redirectUri,
    responseType: 'token id_token',
    scope: 'openid'
  });

  login() {
    this.auth0.authorize();
  }
  constructor() {
    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);
  }

  handleAuthentication() {
    this.auth0.parseHash((err, authResult) => {
      if (authResult && authResult.accessToken && authResult.idToken) {
        this.setSession(authResult);
      } else if (err) {
        history.replace('/admin/dashboard');
        console.info(err);
        alert(`Error: ${err.error}. Check the console for further details.`);
      }
    });
  }

  getAccessToken() {
    return this.accessToken;
  }

  getIdToken() {
    return this.idToken;
  }

  setSession(authResult) {
    // Set isLoggedIn flag in localStorage
    localStorage.setItem('isLoggedIn', 'true');

    // Set the time that the Access Token will expire at
    let expiresAt = (authResult.expiresIn * 1000) + new Date().getTime();
    this.accessToken = authResult.accessToken;
    this.idToken = authResult.idToken;
    this.expiresAt = expiresAt;

    // navigate to the home route
    history.replace('/home');
  }

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

  logout() {
    // Remove tokens and expiry time
    this.accessToken = null;
    this.idToken = null;
    this.expiresAt = 0;

    // Remove isLoggedIn flag from localStorage
    localStorage.removeItem('isLoggedIn');

    this.auth0.logout({
      returnTo: window.location.origin
    });

    // navigate to the home route
    history.replace('/auth/login');
  }

  isAuthenticated() {
    // Check whether the current time is past the
    // access token's expiry time
    let expiresAt = this.expiresAt;
    return new Date().getTime() < expiresAt;
  }
}

Можете ли вы показать свой компонент аутентификации?

iqbal125 31.05.2019 02:35

Конечно, @iqbal125 смотрите обновленный пост с Auth comp внизу.

jedi_chief 31.05.2019 04:09
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
2
2
756
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я делаю это с помощью history.replace() в методах утилиты Auth, а затем перенаправляю на компонент проверки подлинности, который обновляет состояние глобального контекста.

import auth0 from 'auth0-js'
import history from './history';

export default class Auth {
  auth0 = new auth0.WebAuth({
    domain: 'webapp1.auth0.com',
    clientID: 'uZxUdMAsiDWeu3OrNpoi4JwJscdF5nAx',
    redirectUri: 'http://localhost:3000/callback',
    responseType: 'token id_token',
    scope: 'openid profile email'
  })

  userProfile = {}

  login = () => {
      this.auth0.authorize()
  }

  handleAuth = () => {
    this.auth0.parseHash((err, authResult) => {
      if (authResult) {
        localStorage.setItem('access_token', authResult.accessToken)
        localStorage.setItem('id_token', authResult.idToken)

        let expiresAt = JSON.stringify((authResult.expiresIn * 1000 + new Date().getTime()))
        localStorage.setItem('expiresAt', expiresAt)

        this.getProfile();
        setTimeout(() => { history.replace('/authcheck') }, 600);
      } else {
        console.info(err)
      }
    })
  }

  getAccessToken = () => {
    if (localStorage.getItem('access_token')) {
      const accessToken = localStorage.getItem('access_token')
      return accessToken
    } else {
      return null
    }
  }


  getProfile = () => {
    let accessToken = this.getAccessToken()
    if (accessToken) {
      this.auth0.client.userInfo(accessToken, (err, profile) => {
          if (profile) {
            this.userProfile = { profile }
          }
      } )
    }
  }


  logout = () => {
    localStorage.removeItem('access_token')
    localStorage.removeItem('id_token')
    localStorage.removeItem('expiresAt')
    setTimeout(() => { history.replace('/authcheck') }, 200);
  }

  isAuthenticated = () => {
    let expiresAt = JSON.parse(localStorage.getItem('expiresAt'))
    return new Date().getTime() < expiresAt
  }

}


import React, { useEffect, useContext } from 'react';
import history from './history';
import Context from './context';
import * as ACTIONS from '../store/actions/actions';
import axios from 'axios';

const AuthCheck = () => {
  const context = useContext(Context)

  const send_profile_to_db = (profile) => {
   const data = profile
   axios.post('/api/posts/userprofiletodb', data )
    .then(axios.get('/api/get/userprofilefromdb', {params: {email: profile.profile.email}})
      .then(res => context.handleAddDBProfile(res.data)) )
    }

  useEffect(() => {
    if (context.authObj.isAuthenticated()) {
      context.handleUserLogin()
      context.handleUserAddProfile(context.authObj.userProfile)
      send_profile_to_db(context.authObj.userProfile)
      history.replace('/')
    }
    else {
      context.handleUserLogout()
      context.handleUserRemoveProfile()
      history.replace('/')
      }
    }, [])

    return(
        <div>
        </div>
    )}




export default AuthCheck;

Вы можете проверить полностью работающее приложение здесь

https://github.com/iqbal125/react_hooks_fullstack_skeleton

Другие вопросы по теме