如何使用Javascript创建受保护的路由/网址功能?
例如:
网站:mysite.com
。
受保护的网址:mysite.com/admin/PageA
,mysite.com/admin/PageB
或mysite.com/adimin/PageC
功能:
如果未登录的用户并且要访问任何受保护的URL(例如:mysite.com/admin/PageB
),则应将其重定向到mysite.com/login
。
成功登录后,他应被重定向回他要访问的页面。
(找不到任何教程。请提供链接,如果您知道的话)
答案 0 :(得分:0)
实施这样的历史记录模块
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 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 };
});
});
});
}