如何使用 React.js 中的路由进行身份验证
How to authenticate with Routes in React.js
我使用这种方法向用户显示私有页面。问题是没有页面显示给我,但我放入 PrivatePage
的日志工作正常。
Components
是 正确的,因为当我简单地调用路由时,组件被正确返回 但它与 PrivatePage
有问题并且什么都不做。
错误文本:
Error: Objects are not valid as a React child (found: [object
Promise]). If you meant to render a collection of children, use an
array instead.
我必须在用户访问某个地址之前通过服务器验证该用户,因为用户使用该站点有时间限制,所以我使用了Promise
。
function Auth() {
return new Promise((resolve, reject) => {
let appData = GetAppData();
if (appData.UserToken.length == 0) {
reject(-2);
}
let request = {
Token: appData.UserToken,
UserId: appData.UserId
}
axios.post("****UserValidUrl****", request).then(response => {
switch (response.data.Type) {
case 10:
resolve(10);
break;
case -2:
reject(-2);
break;
case -13:
reject(-13);
}
}).catch(err => {
reject(-13);
})
})
}
私人主页:
const PrivatePage = ({children, ...rest}) => (
return <Route
{...rest}
render={async ({location }) => {
let type = 10;
try {
type = await Auth();
} catch(e) {
type = -13;
}
Log(type);
switch (type) {
case 10:
return children;
break
case -2:
return (
<Redirect
to={{
pathname: '/Auth/Login',
state: { from: location },
}}
/>)
case -13:
return (
<Redirect
to={{
pathname: '/NotFound',
state: { from: location },
}}
/>)
break;
}}
}/>
)
基页:
export default function BasePage() {
return (
<div>
<BrowserRouter>
<Switch>
<Route exact path={"/Auth/Login"} component={Login}/>
<PrivatePage path={"/"}>
<Switch>
<Route exact path={"/"} component={Home}/>
<Route exact path={"/Dashboard/Home"} component={Home}/>
<Route exact path={"/Dashboard/Profile"} component={Profile}/>
<Route component={NotFound}/>
</Switch>
}/>
</Switch>
</BrowserRouter>
</div>
);
}
也许你可以在你的私人路线中做这样的事情。
私人主页
const PrivatePage = ({ children, ...rest }) => (
<Route
{...rest}
render={async ({ location }) => {
let isAuthenticated = false;
try {
isAuthenticated = await Auth();
} catch(e) {
// If you want to log the error.
}
if (isAuthenticated) {
return children;
}
return (
<Redirect
to={{
pathname: '/login',
state: { from: location },
}}
/>
);
}}
/>
);
BasePage
export default function BasePage() {
return (
<div>
<BrowserRouter>
<Switch>
<Route exact path={"/Auth/Login"} component={Login}/>
<PrivatePage path={"/"}>
<Switch>
<Route exact path={"/"} component={Home}/>
<Route exact path={"/Dashboard/Home"} component={Home}/>
<Route exact path={"/Dashboard/Profile"} component={Profile}/>
<Route component={NotFound}/>
</Switch>
</PrivatePage>
</Switch>
</BrowserRouter>
</div>
);
}
编辑
PrivatePage 用于 Auth.
中的特定数值
const PrivatePage = ({children, ...rest}) => (
return <Route
{...rest}
render={async ({location }) => {
let authenticated = false;
try {
authenticated = await Auth();
} catch(e) {
// If you want to log the error.
}
if(authenticated === -2) {
// redirect one
} else if (authenticated === -13) {
// redirect two
} if (authenticated) {
return children;
}
return (
<Redirect
to={{
pathname: "/Auth/Login",
state: { from: location },
}}
/>
);
}}
/>
)
您的导航看起来很复杂,无法进行身份验证。您可以将您的组件视为路由并像这样进行路由。
假设您已经单独进行了身份验证,并且您只是检查是否可以进行,而不是每次都尝试对路由进行身份验证。如果您更喜欢在路由上进行此身份验证,仍然适用解决方案。
function AuthenticatedRoute({ children, ...props }) {
const isAuthenticated = useContext(AuthenticationContext);
return isAuthenticated ? (
<Route {...props}>{children}</Route>
) : (
<Redirect
to={{
pathname: '/login',
state: { from: location },
}}
/>
);
}
并像这样使用它:
<AuthenticatedRoute path="/Dashboard/Home" exact>
<h1>Hey Doctor Strange! You made it</h1>
</AuthenticatedRoute>
我也在这个代码沙盒中创建了一个protected auth路由供参考:
https://codesandbox.io/s/cranky-poincare-l2c06?file=/src/App.js:262-488
export default function PrivateRoute({component: Component, ...props}) {
let [PAGE_LOADING, SET_PAGE_LOADING] = useState(LOADING_TYPE.Loading);
let [AUTHENTICATION, SET_AUTHENTICATE] = useState(0);
useEffect(() => {
Auth().then((resolve) => {
SET_AUTHENTICATE(resolve);
}).catch((reject) => SET_AUTHENTICATE(reject))
.then(() => SET_PAGE_LOADING(LOADING_TYPE.Default))
}, [])
return (
PAGE_LOADING === LOADING_TYPE.Loading && AUTHENTICATION == 0 ?
<CtLabel/> :
<Route
{...props}
render={props => (
AUTHENTICATION == 10 ?
<Component {...props}/> :
<Redirect to={ROUTE_PATH.LOGIN}/>
)}/>
)
}
而二手:
export default function BasePage() {
return (
<BrowserRouter>
<Switch>
{/*Other Routes*/}
<Private path={***} component={Home} exact/>
<Private path={***} component={Profile} exact/>
{/*Other Routes*/}
<Route component={NotFound}/>
</Switch>
</BrowserRouter>
);
}
我使用这种方法向用户显示私有页面。问题是没有页面显示给我,但我放入 PrivatePage
的日志工作正常。
Components
是 正确的,因为当我简单地调用路由时,组件被正确返回 但它与 PrivatePage
有问题并且什么都不做。
错误文本:
Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.
我必须在用户访问某个地址之前通过服务器验证该用户,因为用户使用该站点有时间限制,所以我使用了Promise
。
function Auth() {
return new Promise((resolve, reject) => {
let appData = GetAppData();
if (appData.UserToken.length == 0) {
reject(-2);
}
let request = {
Token: appData.UserToken,
UserId: appData.UserId
}
axios.post("****UserValidUrl****", request).then(response => {
switch (response.data.Type) {
case 10:
resolve(10);
break;
case -2:
reject(-2);
break;
case -13:
reject(-13);
}
}).catch(err => {
reject(-13);
})
})
}
私人主页:
const PrivatePage = ({children, ...rest}) => (
return <Route
{...rest}
render={async ({location }) => {
let type = 10;
try {
type = await Auth();
} catch(e) {
type = -13;
}
Log(type);
switch (type) {
case 10:
return children;
break
case -2:
return (
<Redirect
to={{
pathname: '/Auth/Login',
state: { from: location },
}}
/>)
case -13:
return (
<Redirect
to={{
pathname: '/NotFound',
state: { from: location },
}}
/>)
break;
}}
}/>
)
基页:
export default function BasePage() {
return (
<div>
<BrowserRouter>
<Switch>
<Route exact path={"/Auth/Login"} component={Login}/>
<PrivatePage path={"/"}>
<Switch>
<Route exact path={"/"} component={Home}/>
<Route exact path={"/Dashboard/Home"} component={Home}/>
<Route exact path={"/Dashboard/Profile"} component={Profile}/>
<Route component={NotFound}/>
</Switch>
}/>
</Switch>
</BrowserRouter>
</div>
);
}
也许你可以在你的私人路线中做这样的事情。
私人主页
const PrivatePage = ({ children, ...rest }) => (
<Route
{...rest}
render={async ({ location }) => {
let isAuthenticated = false;
try {
isAuthenticated = await Auth();
} catch(e) {
// If you want to log the error.
}
if (isAuthenticated) {
return children;
}
return (
<Redirect
to={{
pathname: '/login',
state: { from: location },
}}
/>
);
}}
/>
);
BasePage
export default function BasePage() {
return (
<div>
<BrowserRouter>
<Switch>
<Route exact path={"/Auth/Login"} component={Login}/>
<PrivatePage path={"/"}>
<Switch>
<Route exact path={"/"} component={Home}/>
<Route exact path={"/Dashboard/Home"} component={Home}/>
<Route exact path={"/Dashboard/Profile"} component={Profile}/>
<Route component={NotFound}/>
</Switch>
</PrivatePage>
</Switch>
</BrowserRouter>
</div>
);
}
编辑
PrivatePage 用于 Auth.
中的特定数值const PrivatePage = ({children, ...rest}) => (
return <Route
{...rest}
render={async ({location }) => {
let authenticated = false;
try {
authenticated = await Auth();
} catch(e) {
// If you want to log the error.
}
if(authenticated === -2) {
// redirect one
} else if (authenticated === -13) {
// redirect two
} if (authenticated) {
return children;
}
return (
<Redirect
to={{
pathname: "/Auth/Login",
state: { from: location },
}}
/>
);
}}
/>
)
您的导航看起来很复杂,无法进行身份验证。您可以将您的组件视为路由并像这样进行路由。
假设您已经单独进行了身份验证,并且您只是检查是否可以进行,而不是每次都尝试对路由进行身份验证。如果您更喜欢在路由上进行此身份验证,仍然适用解决方案。
function AuthenticatedRoute({ children, ...props }) {
const isAuthenticated = useContext(AuthenticationContext);
return isAuthenticated ? (
<Route {...props}>{children}</Route>
) : (
<Redirect
to={{
pathname: '/login',
state: { from: location },
}}
/>
);
}
并像这样使用它:
<AuthenticatedRoute path="/Dashboard/Home" exact>
<h1>Hey Doctor Strange! You made it</h1>
</AuthenticatedRoute>
我也在这个代码沙盒中创建了一个protected auth路由供参考: https://codesandbox.io/s/cranky-poincare-l2c06?file=/src/App.js:262-488
export default function PrivateRoute({component: Component, ...props}) {
let [PAGE_LOADING, SET_PAGE_LOADING] = useState(LOADING_TYPE.Loading);
let [AUTHENTICATION, SET_AUTHENTICATE] = useState(0);
useEffect(() => {
Auth().then((resolve) => {
SET_AUTHENTICATE(resolve);
}).catch((reject) => SET_AUTHENTICATE(reject))
.then(() => SET_PAGE_LOADING(LOADING_TYPE.Default))
}, [])
return (
PAGE_LOADING === LOADING_TYPE.Loading && AUTHENTICATION == 0 ?
<CtLabel/> :
<Route
{...props}
render={props => (
AUTHENTICATION == 10 ?
<Component {...props}/> :
<Redirect to={ROUTE_PATH.LOGIN}/>
)}/>
)
}
而二手:
export default function BasePage() {
return (
<BrowserRouter>
<Switch>
{/*Other Routes*/}
<Private path={***} component={Home} exact/>
<Private path={***} component={Profile} exact/>
{/*Other Routes*/}
<Route component={NotFound}/>
</Switch>
</BrowserRouter>
);
}