V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
sciel
V2EX  ›  问与答

想用 nextjs+swr+Material-UI 做个后台管理系统,请问路由守卫和用户鉴权如何做比较好呢?

  •  
  •   sciel · 135 天前 · 873 次点击
    这是一个创建于 135 天前的主题,其中的信息可能已经有所发展或是发生改变。

    大家好,我想用 nextJs 做个后台管理系统。但路由守卫和用户鉴权这里没太搞好,特别是在 Layout 组件里面(渲染用户可访问的菜单)。

    现在我是这样做的

    登录

    用户登录后将用户的信息保存到 localStrorage 里面,其中保存了用户的基本信息,token ,及用户的可访问 menus 。然后跳转到主页

    localStorage.setItem(KeyUser, JSON.stringify(data))
    toast.success('success', {
       autoClose: successTime, onClose: () => {
           Router.push('/')
       }
    })
    

    _app.js

    _app.js页面的基本布局这里会使用 Layout 组件进行用户可访问的菜单渲染。代码如下

    import {Layout} from "../components/Layout";
    
    function MyApp({Component, pageProps, router}) {
    	...
        if (router.route === '/login') return <><Component {...pageProps} /></>
        return <ThemeProvider theme={theme}>
            <Layout dark={dark} setDark={handleSetDark} theme={theme}>
                <Component {...pageProps} />
            </Layout>
            <ToastContainer position={'top-center'} theme={'dark'}/>
        </ThemeProvider>
    }
    

    Layout.js

    问题主要在这里,如果直接将 localStorage 的用户信息删除,由于useUser里没有判断到用户信息为空而跳转到login页面,所以继续向Layout组件里面走了。

    这里的前两个 if 条件也不能阻止程序往下执行所以 {menus.map 里面回报 undefined.

    (其实我有在 useUser 里面做判断,如果用户信息不存在直接到/login页面。但没有起效果)

    export const Layout = ({children, dark, setDark, theme}) => {
        const {menus, u, mutate, loading, token, loggedOut} = useUser()
        if (loading) return <>{children}</>
        if (!u) return <></>
        ...
        return (<Box sx={{display: 'flex'}}>
        	<List>
            {menus.map(item)=> ...}
            </List>
            ...
            {childlren}
            ...
        </Box>);
    }
    

    useUser.js

    这是useUser.js用来获取用户的信息,如果用户没有登录就直接跳到登录页面。

    获取用户信息是从localStorage里面进行获取的,参照官网的 demo 中改来。

    ...
    const userFetcher = async () => {
        let u = localStorage.getItem(KeyUser)
        if (isEmpty(u)) {
            let error = new Error("Not authorized!");
            error.status = 403
            throw error
        }
        return JSON.parse(u)
    }
    export const useUser = () => {
        const {data, mutate, error} = useSWR(`api_user`, userFetcher)
        const loggedOut = error && error.status === 403;
        const loading = loggedOut === undefined || !data && !error;
        if (loggedOut) {
            Router.push('/login')
        }
        if (data) {
            const {u, menus, token} = data.data
            return {loading, mutate, u, menus, token, loggedOut}
        }
        return {loading, loggedOut}
    }
    

    所以想请问一下大家这块如何做比较好呢?

    刚学 react,nextjs 没多久,请多指教呀 ^_^。

    6 条回复    2022-01-03 18:29:11 +08:00
    adjusted
        1
    adjusted  
       135 天前
    sciel
        2
    sciel  
    OP
       135 天前
    @adjusted 没有,一会去看看哈,谢谢。
    walpurgis
        3
    walpurgis  
       135 天前 via iPhone
    服务端渲染的页面建议把用户登录态放到 cookie 里
    jielong
        4
    jielong  
       135 天前
    用了 next 最好能做到服务端渲染阶段拿到用户信息,不然感觉会很奇怪 😅

    推荐这两个库,用户信息,token 放 cookie ,能在 serverSide 拿到

    https://github.com/bjoluc/next-redux-cookie-wrapper
    https://github.com/kirill-konshin/next-redux-wrapper
    sciel
        5
    sciel  
    OP
       135 天前
    @walpurgis
    @jielong 之前试过服务端渲染,但后台给自己用的没必要,所以还是放客户端好做点。方便在 localStorage 里面取数据。 试过放 cookie 里,但 cookie 里面存的信息有限,用户 menus 放不下。
    page470075640
        6
    page470075640  
       135 天前 via iPhone
    我的做法是登入后的页面会去拉取用户信息 如果拿不到就重定向 login 页面
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   4059 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 01:44 · PVG 09:44 · LAX 18:44 · JFK 21:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.