Preventing Routing in Response when a user manually changes the URL on a browser tab

I am stuck in a problem that occurs when the user manually changes the route on the browser tab and presses the enter key. This causes my responsive router to transition to the state entered by the user. I want to prevent this and only allow routing through the stream, which I implemented by clicking a button on my website.

Some of my screens need data that will only be available if the user navigates the site using the expected stream. If the user directly tries to go to a specific route by manually changing the route in the URL, he can skip the desired stream and, therefore, the application will break.

Another scenario, if I want to restrict the access of some users to certain routes, but the user knows the path and manually enters this into the browser URL, then it will be presented with this screen, but it should not be.

+12
source share
4 answers

You can create route protection using the HOC. For example, you do not want an unauthorized user to go the route /profile, then you can do the following:

// requireAuthorized.js (HOC)
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import {connect} from 'react-redux'
import {Redirect} from 'react-router-dom'

const connector = connect(
  state => ({
    isAuthorized: state.profile !== null // say, you keep user profile in redux
  })
)

export default (WrappedComponent) => {
  return (
    connector(
      class extends Component {
        static propTypes = {
          isAuthorized: PropTypes.bool.isRequired
        }

        render () {
          const {isAuthorized, ...clearedProps} = this.props
          if (isAuthorized) {
            return <WrappedComponent {...clearedProps} />
          } else {
            return <Redirect to={{pathname: '/login'}} />
          }
        }
      }
    )
  )
}


// ProfilePage.jsx
import React from 'react'
...
import requireAdmin from '../hocs/requireAdmin' // adjust path

class ProfilePage extends React.Component {
  ...
  render () {
    return (
      <div>
        ...
      </div>
    )
  }
}

export default requireAdmin(ProfilePage)

Pay attention to the export instruction in ProfilePage.js

+1
source

- . HOC Route /. . , .. menu/menuItem.

import requireAuth from "../components/login/requireAuth";

class Routes extends React.Component<RoutesProps, {}> {
    render() {
        return (
            <div>
                <Switch>
                    <Route exact={true} path="/" component={requireAuth(Persons, ["UC52_003"])} />
                    <Route path="/jobs" component={requireAuth(Jobs, ["UC52_006"])} />
                </Switch>
            </div>
        )
    }
}


export default function (ComposedComponent, privileges) {

    interface AuthenticateProps {
        isAuthenticated: boolean
        userPrivileges: string[]
    }
    class Authenticate extends React.Component<AuthenticateProps, {}> {
        constructor(props: AuthenticateProps) {
            super(props)
        }

        render() {
            return (
                isAuthorized(this.props.isAuthenticated, privileges, this.props.userPrivileges) &&
                <ComposedComponent {...this.props} /> || <div>User is not authorised to access this page.</div>
            );
        }
    }

    function mapStateToProps(state) {
        return {
            isAuthenticated: state.userContext ? state.userContext.isAuthenticated : false,
            userPrivileges: state.userContext ? state.userContext.user ? state.userContext.user.rights : [] : []
        };
    }

    return connect(mapStateToProps, null)(Authenticate);
}
+1

, , ( , :) -), - .

+1

(, , ).

HOC:

export const withAuth = connectedReduxRedirect({
    redirectPath: '/login',
    authenticatedSelector: state => state.user.isAuthenticated, // or whatever you use
    authenticatingSelector: state => state.user.loading,
    wrapperDisplayName: 'UserIsAuthenticated'
});

HOC:

export const withFlow = (step) = connectedReduxRedirect({
    redirectPath: '/initial-flow-step',
    authenticatedSelector: state => state.flow[step] === true,
    wrapperDisplayName: 'FlowComponent'
});

const AuthenticatedComponent = withAuth(Dashboard)
const SecondStepComponent = withFlow("first-step-finished")(SecondStep)
const ThirdStepComponent = withFlow("second-step-finished")(ThirdStep)

You can easily create an authenticated stream step by composing an HOC:

const AuthSecondStepComponent = withAuth(withFlow("first-step-finished")(SecondStep))

The only thing that is important is that you correctly update your state of reduction during the step. When the user completes the first step, you will install

state.flow["first-step-finished"] = true // or however you manage your state

so that when the user manually goes to a specific page, he does not have such a state of redundancy, since it was in memory and was redirected to the route redirectPath.

0
source

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


All Articles