使用JavaScript的受保护的路由或网址功能

时间:2018-08-10 05:42:02

标签: javascript reactjs

如何使用Javascript创建受保护的路由/网址功能?

例如:

网站:mysite.com

受保护的网址:mysite.com/admin/PageAmysite.com/admin/PageBmysite.com/adimin/PageC

功能:

  1. 如果未登录的用户并且要访问任何受保护的URL(例如:mysite.com/admin/PageB),则应将其重定向到mysite.com/login

  2. 成功登录后,他应被重定向回他要访问的页面。

(找不到任何教程。请提供链接,如果您知道的话)

1 个答案:

答案 0 :(得分:0)

没有React

实施这样的历史记录模块

export type HistoryHandle = {
  window: Object,
};

export const actions = {
  PUSH: 'HISTORY:PUSH',
  POP: 'HISTORY:POP',
};

const HISTORY_STATE_CHANGE = 'HistoryStateChange';

export const listen = (
  handle: HistoryHandle,
  callback: (location: string, action: string) => any,
)) => {
  const listener = e => {
    callback(window.location.pathname, e.detail);
  };
  handle.window.addEventListener(HISTORY_STATE_CHANGE, listener);
  return () => {
    handle.window.removeEventListener(HISTORY_STATE_CHANGE, listener);
  };
};

export const push = (
  handle: any,
  route: string,
  state?: Object,
  title?: string,
) => {
  handle.window.history.pushState(state, title, route);
  handle.window.dispatchEvent(
    new CustomEvent(HISTORY_STATE_CHANGE, { detail: actions.PUSH }),
  );
};

let initialized = false;
export function init(window: Object): HistoryHandle {
  const handle = { window };
  if (initialized) {
    return handle;
  }
  handle.window.addEventListener('popstate', () => {
    handle.window.dispatchEvent(
      new CustomEvent(HISTORY_STATE_CHANGE, { detail: actions.POP }),
    );
  });
  initialized = true;
  return handle;
}

有了“历史记录”模块,您可以收听更改

listen().then(changedPath => {
  const match = routes.filter(r => {
    return r.path === changedPath;
  }); // Make sure you render a 404 if the filter doesn't return any matched route

  return match.enter().then(isAuthenicated => {
    return { component: match.component };
  });
});

每个路由都具有一个enter钩子,就像React Router一样。

const protectedRoute = {
  path: '/dashboard',
  component: Dashboard,
  enter() {
    return isUserLoggedInPromise()
  }
}

使用React

您可以使用这样的东西实现自己的简单React Router

class MyRouter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      component: Root
    }
  }
  componentDidMount() {
  }
  ...
}

现在的挑战是,我们可以不按推就监听历史弹出状态。这就是为什么我们需要上面的“历史记录”模块的原因。因此,您必须首先实现Link组件。这样您就可以捕获推送和弹出状态操作。为简洁起见,我一直没有回答过历史API的实现。

export function Link(props: {
  to: string,
  onClick: (e: Event) => ?boolean,
  children: React.Node,
}) {
  const { to, onClick, children } = props;
  function handleOnClick(e: Event) {
    e.preventDefault();
    if (typeof window !== 'undefined') {
      const history = History.init(window);
      History.push(history, to);
    }
    onClick && onClick(e);
  }

  return (
    <a href={to} onClick={handleOnClick}>
      {children}
    </a>
  );
}

一旦有办法,我们可以如下修改MyRouter.componentDidMount

 componentDidMount() {
    // For brevity, I'm keep the implementation of listen out of this answer.
    listen().then(changedPath => {
      // With listen in place, now its all a matter of accepting routes in props.
      const { routes } = this.props;
      const match = routes.filter(r => {
        return r.path === changedPath;
      }); // Make sure you render a 404 if the filter doesn't return any matched route

      this.setState(() => {
        return { component: match.component };
      });
    });
  }


  render() {
     return this.state.component;
  }

要应用身份验证,路由也可以像React Router一样通过输入挂钩。

const protectedRoute = {
  path: '/dashboard',
  component: Dashboard,
  enter() {
    return isUserLoggedInPromise()
  }
}

因此,如下修改componentDidMount:

  componentDidMount() {
    // For brevity, I'm keep the implementation of listen out of this answer.
    listen().then(changedPath => {
      // With listen in place, now its all a matter of accepting routes in props.
      const { routes } = this.props;
      const match = routes.filter(r => {
        return r.path === changedPath;
      }); // Make sure you render a 404 if the filter doesn't return any matched route

      match.enter().then(isAuthenicated => {
        this.setState(() => {
          return { component: match.component };
        });
      });
    });
  }