【发布时间】:2021-02-16 02:38:06
【问题描述】:
我正在开发一个具有公共和管理路由的应用程序,在我们过去的 CRA 应用程序中,我们使用了自定义路由元素,但我们在 nextjs 中没有细化...我们有很多公共页面,并且我们有 20 个私人页面/路线。
在 nextjs 中处理受保护的认证路由和公共路由的最佳方法是什么?
非常感谢! 最好的
【问题讨论】:
我正在开发一个具有公共和管理路由的应用程序,在我们过去的 CRA 应用程序中,我们使用了自定义路由元素,但我们在 nextjs 中没有细化...我们有很多公共页面,并且我们有 20 个私人页面/路线。
在 nextjs 中处理受保护的认证路由和公共路由的最佳方法是什么?
非常感谢! 最好的
【问题讨论】:
非常感谢@AleXiuS 的回答! 对于那些想要将此 hoc 与 typescript 一起使用的人,我已将您的解决方案和 great article 混合在一起:
import { NextComponentType } from "next";
function withAuth<T>(Component: NextComponentType<T>) {
const Auth = (props: T) => {
// Login data added to props via redux-store (or use react context for example)
const { isLoggedIn } = props;
// If user is not logged in, return login component
if (!isLoggedIn) {
return <Login />;
}
// If user is logged in, return original component
return <Component {...props} />;
};
// Copy getInitial props so it will run as well
if (Component.getInitialProps) {
Auth.getInitialProps = Component.getInitialProps;
}
return Auth;
}
export default withAuth;
【讨论】:
这是typescript版本,你可以将允许的权限传递给HOC,并与登录用户现有的权限进行比较。
export interface ProtectedComponentProps {
requiredPermission: string;
}
const ProtectedComponent: React.FC<ProtectedComponentProps> = (props) => {
const [isAuthorized, setIsAuthorized] = useState<boolean>();
useEffect(() => {
const permissions = authService.getPermissions();
setIsAuthorized(permissions.includes(props.requiredPermission))
}, []);
return (
<>
{isAuthorized ? props.children : <p>not authorized</p>}
</>
);
}
export default ProtectedComponent;
并像这样使用它:
<ProtectedComponent requiredPermission="permissionName">
<SomeProtectedComponent />
</ProtectedComponent>
【讨论】:
除了使用 HOC 的解决方案之外,您还可以使用接下来的 ssr 方法,例如 getServerSideProps, 在这种情况下,您必须修改您的登录功能以在您的申请中设置标题(此标题将说明您是否已登录) 像这样:
const signIng = async() =>{
...
api.defaults.headers.someTokenName = token; //Here you can set something just to identify that there is something into someTokenName or your JWT token
...
}
然后在你的 withAuth 组件中:
const WithAuth = (): JSX.Element => {
// ... your component code
}
export const getServerSideProps: GetServerSideProps = async(ctx) => {
const session = await ctx.req.headers['someTokenName'];
if(!session){
return{
redirect:{
destination: '/yourhomepage', //usually the login page
permanent: false,
}
}
}
return{
props: {
authenticated: true
}
}
}
这应该可以防止您的 Web 应用程序从未验证到已验证闪烁
【讨论】:
我认为这取决于页面的类型。
对于静态生成的页面:
您可以像 @AleXius 建议的那样使用 HOC 进行身份验证。
对于服务器端呈现的页面:
您可以在getServerSideProps 中执行您的身份验证逻辑。
export async function getServerSideProps(context) {
const sendRedirectLocation = (location) => {
res.writeHead(302, {
Location: location,
});
res.end();
return { props: {} }; // stop execution
};
// some auth logic here
const isAuth = await authService('some_type_of_token')
if (!isAuth) {
sendRedirectLocation('/login')
}
return {
props: {}, // will be passed to the page component as props
}
}
对于带有自定义服务器的服务器端渲染页面:
取决于您选择的服务器,您可以选择不同的解决方案。对于 Express,您可能可以使用 auth 中间件。如果你愿意,也可以在getServerSideProps处理。
【讨论】:
getServerSideProps?
getServerSideProps 中重用的身份验证逻辑,如Creating a HOC (higher order component) for cookies in nextJS 中所述。
我个人一直在为此使用 HOC(高阶组件)。
这是一个示例身份验证 HOC:
const withAuth = Component => {
const Auth = (props) => {
// Login data added to props via redux-store (or use react context for example)
const { isLoggedIn } = props;
// If user is not logged in, return login component
if (!isLoggedIn) {
return (
<Login />
);
}
// If user is logged in, return original component
return (
<Component {...props} />
);
};
// Copy getInitial props so it will run as well
if (Component.getInitialProps) {
Auth.getInitialProps = Component.getInitialProps;
}
return Auth;
};
export default withAuth;
您可以将此 HOC 用于任何页面组件。 下面是一个使用示例:
const MyPage = () => (
<> My private page</>
);
export default withAuth(MyPage);
如果需要,您可以扩展 withAuth HOC 并使用角色检查,例如公共、普通用户和管理员。
【讨论】: