apple2026
V2EX  ›  问与答

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

  •  
  •   apple2026 · Jan 3, 2022 · 3940 views
    This topic created in 1620 days ago, the information mentioned may be changed or developed.

    大家好,我想用 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 replies    2022-01-03 18:29:11 +08:00
    adjusted
        1
    adjusted  
       Jan 3, 2022
    apple2026
        2
    apple2026  
    OP
       Jan 3, 2022
    @adjusted 没有,一会去看看哈,谢谢。
    walpurgis
        3
    walpurgis  
       Jan 3, 2022 via iPhone
    服务端渲染的页面建议把用户登录态放到 cookie 里
    jielong
        4
    jielong  
       Jan 3, 2022
    用了 next 最好能做到服务端渲染阶段拿到用户信息,不然感觉会很奇怪 😅

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

    https://github.com/bjoluc/next-redux-cookie-wrapper
    https://github.com/kirill-konshin/next-redux-wrapper
    apple2026
        5
    apple2026  
    OP
       Jan 3, 2022
    @walpurgis
    @jielong 之前试过服务端渲染,但后台给自己用的没必要,所以还是放客户端好做点。方便在 localStorage 里面取数据。 试过放 cookie 里,但 cookie 里面存的信息有限,用户 menus 放不下。
    page470075640
        6
    page470075640  
       Jan 3, 2022 via iPhone
    我的做法是登入后的页面会去拉取用户信息 如果拿不到就重定向 login 页面
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   3193 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 55ms · UTC 12:27 · PVG 20:27 · LAX 05:27 · JFK 08:27
    ♥ Do have faith in what you're doing.