React - What is the best way to handle login and authentication?

New for reacting and working with an authentication / logging application. It currently works, but it has been hacked. Right now I have my state isAuthenticatedlocated in mine routes.js, for example:

class Routes extends Component {

    constructor(props) {
        super(props);

        this.state = {
            isAuthenticated: false,
         }
     }

On my login page, I need to know when the user is authenticated in order to redirect them to the page home. What is the best design pattern to access and manage this state isAuthenticated? As I configured it, I have a function that sets the state inside routes.jsand sends the state as a propeller like this:

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

and lower in the router ...

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

, , , , . , , login.js, . isAuthenticated ? , .

: isAuthenticated , /.

+9
4

isAuthenticated state , , . ! :)

, , access_token ( ) localStorage cookies localStorage . access_token , access_token , . access_token , , , , , .

access_token , .


access_token refresh_token - , , .

, , OAuth2, . OAuth2 , . , 1) access_token, , 2) refresh_token, (, ). access_token access_token , , , refresh_token , access_token .


cookies localStorage - !

localStorage - . /, access_token . . /, , expires, .

, cookies expires, , . cookies - , , js-cookie, cookies.

cookies: - ! login.mycompany.com - app.mycompany.com, cookie . LocalStorage.


React, :

isAuthenticated()

import Cookies from 'js-cookie'

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

()

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
  }
}
+18

. , API

+3

isAuthenticated, , , devtools . true, .

+2

, , . , , .

Here is an example of using React Context, where we create a context with createContextand use Consumerto access it through the 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> 
Run code

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

+1
source

Source: https://habr.com/ru/post/1696158/


All Articles