首页 > 解决方案 > 如何自动登录或重定向?

问题描述

我没有使用@nuxtjs/auth,只是简单的代码......

我有一个客户端插件可以在页面刷新时自动登录用户

// FILE ./plugins/auth.client.js
export default async function ({ $axios, store, redirect, route }) {
    console.log('[PLUGIN] Auth (Client)')

    try {
        const token = localStorage.getItem('sc-token')
        store.commit('auth/setAuth', token)

        if (!token) {
            console.log('redirecting... 1')
            return redirect(401, '/auth/login?1')
        }

        const user = await $axios.$post('/api/auth/verify', token)
        console.log('USER', user)

        if (!user) {
            console.log('redirecting... 2')
            return redirect(401, '/auth/login?2')
        }
    } catch (e) {
        return redirect(401, '/auth/login')
    }
}

并且正确设置plugins: [{ src: '~/plugins/auth.client' }]nuxt.config.js

我的问题是,redirect()只有当它在服务器端运行并且我只能localStorage在客户端模式下访问时才有效,另外,服务器总是首先运行,但我试图在知道我是否需要重定向之前附加令牌或不是

你们是怎么做到的?

标签: nuxt.js

解决方案


终于让它按预期工作了,必须./plugins/auth.js./middleware/authenticated.js两者结合使用完全相同的代码

./middleware/authenticated.js每次路由更改都会运行(非常适合检查令牌验证)

./plugins.js在用户刷新页面时运行在客户端和服务器上

为了使所有使用这两个文件的工作,我必须:

  • 停止使用 localStorage 并改用 cookie
  • 使用cookie-universal-nuxt
  • 它将为您提供this.$cookies并且可以在中间件上运行,无论是在客户端模式还是服务器模式下运行

对于每个路由更改,中间件在年龄刷新时验证令牌(用于回火、过期等),插件检查相同

代码./plugins/auth.js

export default async function ({ $axios, store, redirect, app }) {
    console.log('[PLUGIN] Auth (Server/Client)', process.client)

    const path = app && app.router && app.router.currentRoute ? app.router.currentRoute.fullPath : ''

    try {
        const token = app.$cookies.get('sc-token')
        const isLoggedIn = store.getters['auth/isLoggedIn']

        // console.log('[PLUGIN] Auth: token', token)
        // console.log('[PLUGIN] Auth: isLoggedIn', isLoggedIn)

        // token exists?
        if (!token) {
            store.commit('auth/clearAuth')
            return redirect(`/auth/login?path=${path}&err=no_token`)
        }

        // verify token
        try {
            // $axios.defaults.headers.common.Authorization = `Bearer ${token}`
            const user = await $axios.$post('/api/auth/verify', { token })

            // console.log('[PLUGIN] Auth RES OK', user.verified, isLoggedIn)
            // all OK
            if (user.verified && !isLoggedIn) {
                console.log('SETTING AUTH', token)
                store.commit('auth/setAuth', token)
                // return redirect(path)
            }
        } catch (err1) {
            console.log('[PLUGIN] Auth ERROR (1)', err1.message)
            // console.log('redirecting... 2', err1.response.data)

            let message = err1.message
            if (
                err1.response &&
                err1.response.data &&
                err1.response.data.error &&
                err1.response.data.error === 'jwt expired'
            )
                message = 'token_expired'

            store.commit('auth/clearAuth')
            return redirect(`/auth/login?path=${path}&err=${message}`)
        }

        // console.log('COOKIES END')
    } catch (err2) {
        console.log('[PLUGIN] Auth ERROR (2)', err2.message)
        return redirect(401, `/auth/login?err=${err2.message}`)
    }
}

我的/auth/verifyAPI 路线:

const verifyToken = (req, res) => {
    const token = req.body.token || req.headers.authorization.replace('Bearer ', '')

    try {
        const verified = jwt.verify(token, SECRET_SIGN, { issuer: 'https://auth.domain.com/the-editor' })
        res.json({ verified })
    } catch (err) {
        res.status(401).json({ error: err.message })
    }
}

然后,我的 ExpressJs 中间件为每个调用验证令牌,并将令牌有效负载附加到请求中(这样我以后可以接听电话)

const authentication = (req, res, next) => {
    // authentication
    const url = req.url
    let token = req.body.token || req.headers.authorization || req.headers.cookie

    // console.log('[Authentication Express Middleware] headers', JSON.stringify(req.headers))
    // console.log('[Authentication Express Middleware] cookie', JSON.stringify(req.headers.cookie))
    // console.log('[Authentication Express Middleware] body', JSON.stringify(req.body))
    // console.log('[Authentication Express Middleware]', url, !!token)

    // bypass URL as there's no token yet...
    if (['/auth/login'].includes(url)) return next()

    // not the login path, we should validate token
    if (token) {
        if (token.includes('sc-token=')) token = token.replace('sc-token=', '')

        // check and validate token
        token = token.indexOf('Bearer ') === 0 ? token.substring(7) : token // "Bearer ..."
        return jwt.verify(token, SECRET_SIGN, (err, payload) => {
            // attach payload to user (will be null if not verified)
            req.user = payload

            // if verified, err is null and will continue to the next middleware
            return next(err)
        })
    }

    return next(new Error('No valid token was passed'))
}

推荐阅读