Используя 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 смотрите обновленный пост с Auth comp внизу.
Я делаю это с помощью 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;
Вы можете проверить полностью работающее приложение здесь
Можете ли вы показать свой компонент аутентификации?