web-dev-qa-db-fra.com

React - Quel est le meilleur moyen de gérer l'état authentifié/connecté?

Nouveau pour réagir et travailler sur une application avec authentification/connexion. Il fonctionne actuellement mais se sent piraté ensemble. En ce moment, mon état isAuthenticated est situé dans mon routes.js comme suit:

class Routes extends Component {

    constructor(props) {
        super(props);

        this.state = {
            isAuthenticated: false,
         }
     }

Sur ma page de connexion, je dois savoir quand un utilisateur est authentifié pour le rediriger vers la page home. Quel est le meilleur modèle de conception permettant l'accès et la manipulation de cet état isAuthenticated? Comme je l'ai actuellement configuré, j'ai une fonction qui définit l'état dans le routes.js et envoie l'état en tant qu'accessoire comme ceci:

 setAuthenticated = (isAuthenticated) => {
        this.setState({isAuthenticated});
    }

et en bas dans le routeur ...

<Route path="/" exact component={() =>
                            <div>
                                <Login
                                    isAuthenticated={this.state.isAuthenticated}
                                    setAuthenticated={this.setAuthenticated}
                            </div>
                        } />

Oui, je comprends que ce soit une mauvaise conception, car cela modifie des valeurs d'accessoires supposées immuables. Cela est également grave car lorsque je modifie cette valeur dans mon login.js, plusieurs rediffusions inutiles sont générées. Devrais-je déclarer isAuthenticated comme un type de variable globale? En passant, je n’utilise aucune gestion d’État.

Edit: Je configure isAuthenticated en fonction d’une réponse de mon serveur confirmant la combinaison correcte login/mot de passe.

5
Vincent Nguyen

La manipulation de isAuthenticated uniquement dans l'état de votre application signifie que l'utilisateur ne sera pas authentifié chaque fois qu'il actualisera la page. Au lieu de cela, la page de connexion pourrait définir un jeton dans les cookies ou le stockage local pour prouver que l'utilisateur est authentifié. Ensuite, vous pouvez vérifier cette valeur dans les autres pages. En outre, vous aurez probablement besoin d'un jeton pour récupérer les données sur votre serveur (en passant le jeton dans l'en-tête des demandes).

Voici certaines des méthodes et des composants spéciaux que j'utilise pour l'authentification.

isAuthenticated ()

import Cookies from 'js-cookie'

export const getAccessToken = () => Cookies.get('access_token')
export const getRefreshToken = () => Cookies.get('refresh_token')
export const isAuthenticated = () => !!getAccessToken()

authentifier()

export const authenticate = async () => {
  if (getRefreshToken()) {
    try {
      const tokens = await refreshTokens() // call an API, returns tokens

      const expires = (tokens.expires_in || 60 * 60) * 1000
      const inOneHour = new Date(new Date().getTime() + expires)

      // you will have the exact same setters in your Login page/app too
      Cookies.set('access_token', tokens.access_token, { expires: inOneHour })
      Cookies.set('refresh_token', tokens.refresh_token)

      return true
    } catch (error) {
      redirectToLogin()
      return false
    }
  }

  redirectToLogin()
  return false
}

redirectToLogin ()

const redirectToLogin = () => {
  window.location.replace(
    `${getConfig().LOGIN_URL}?next=${window.location.href}`
  )
  // or history.Push('/login') if your Login page is inside the same app
}

AuthenticatedRoute

export const AuthenticatedRoute = ({
  component: Component,
  exact,
  path,
}) => (
  <Route
    exact={exact}
    path={path}
    render={props =>
      isAuthenticated() ? (
        <Component {...props} />
      ) : (
        <AuthenticateBeforeRender render={() => <Component {...props} />} />
      )
    }
  />
)

AuthenticateBeforeRender

class AuthenticateBeforeRender extends Component {
  state = {
    isAuthenticated: false,
  }

  componentDidMount() {
    authenticate().then(isAuthenticated => {
      this.setState({ isAuthenticated })
    })
  }

  render() {
    return this.state.isAuthenticated ? this.props.render() : null
  }
}
4
GG.

Si vous utilisez une application où l'authentification ne dure que pour une session, son stockage en état suffit. Mais notez que cela signifie que l'utilisateur perdra le statut authentifié lors de l'actualisation de la page. 

Voici un exemple d'utilisation de React Context, dans lequel nous créons un contexte à l'aide de createContext et utilisons Consumer pour y accéder via l'application.

const AuthenticationContext = React.createContext();
const { Provider, Consumer } = AuthenticationContext;

function Login(props) {
  return (
    <Consumer>
      {
        value=>
        <button onClick={value.login}>Login</button>
      }
    </Consumer>
  );
}

function Logout() {
  return (
    <Consumer>
      {
        value=>
        <button onClick={value.logout}>Logout</button>
      }
    </Consumer>
  );
}

function AnotherComponent() {
  return (
    <Consumer>
      {
        value=>{
          return value.isAuthenticated?
            <p>Logged in</p>:
            <p>Not Logged in</p>
        }
      }
    </Consumer>
  );
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.login = ()=> {
      this.setState({
        isAuthenticated: true
      });
    }
    this.logout = ()=> {
      this.setState({
        isAuthenticated: false
      });
    }
    this.state = {
      isAuthenticated: false,
      login: this.login,
      logout: this.logout
    }
  }
  
  render() {
    return (
      <Provider value={this.state}>
        <Login />
        <Logout />
        <AnotherComponent />
      </Provider>
    );
  }
}
ReactDOM.render(<App />, document.getElementById("root"));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div> 

https://reactjs.org/docs/context.html#reactcreatecontext

2

vous pouvez définir le jeton d'accès dans la mémoire de stockage locale lors de la connexion et l'effacer après la déconnexion de l'utilisateur. La méthode is authentifiée sera ensuite utilisée pour vérifier s'il y a un jeton et si le jeton est valide lors d'un appel d'API.

1
Waweru Mwaura