【问题标题】:Nuxt.js - retrieving and storing bearer token server sideNuxt.js - 检索和存储承载令牌服务器端
【发布时间】:2021-03-11 13:33:02
【问题描述】:

我正在开发一个 Nuxt 项目(第一次),我使用的 API 要求我们通过客户端 oAuth2 进行身份验证。该应用程序拥有客户端 ID 和客户端密码,但我不想将这些数据暴露给用户。

我的计划是使用 oAuth 令牌端点在服务器端检索生成的不记名令牌。然后我可以将生成的令牌本地存储在文件系统上并将其推送给用户。

我遇到的问题是我不知道如何最好地存储不记名令牌。我创建了一个serverMiddleware,我正在尝试使用 FS 将生成的令牌写入文件。问题是我实际上似乎无法使用 FS,因为它在需要时会引发错误。我认为 serverMiddleware 的想法是它始终在服务器端运行?

我明白了-

[HMR] bundle 'client' has 1 warnings
client.js?1b93:196 ./middleware/server/bearerToken.tsModule not found: Error: Can't resolve 'fs' in '/middleware/server'

这是我创建的中间件 -

const myServerMiddleware = (req, res, next) => {

    try {
        const fs = require('fs');

        // ToDo: read and/or generate bearer token

    } catch (e) {
        console.log('No FS available', e);
    }

    next();
};

export default {
    path: '/',
    handler: myServerMiddleware,
    mode: 'server'
};

这是使用 -

在我的配置中加载的
{
  serverMiddleware: [
    '@/middleware/server/bearerToken.ts'
  ],
}

我希望有人可以在这里为我指明正确的方向!

【问题讨论】:

    标签: nuxt.js


    【解决方案1】:

    对于同一条船上的任何人......

    服务器中间件似乎没有减少它,但普通中间件可以。认为这可能对某人有用...

    在我的nuxt.config.js 中,我定义了 API 的身份验证参数并设置了路由器应该使用的中间件。这些实际上是在运行时从.env 文件加载的:

        // Public variables
        publicRuntimeConfig: {
            apiUrl: process.env.API_URL,
            name: process.env.APP_NAME
        },
    
        // Private variables
        privateRuntimeConfig: {
            apiClientId: process.env.API_CLIENT,
            apiClientSecret: process.env.API_SECRET,
        },
    
        // Apply global middleware to our routing.
        router: {
            middleware: [
                'bearer-token'
            ],
        },
    

    现在是中间件。我在中间件文件夹中创建了一个名为bearer-token.ts 的文件,它使用上面的配置自动启用它。事实证明,在这个执行阶段,您实际上可以通过检查process.server 是否为真来检查我们是处于服务器级别还是客户端级别。只要我们在服务器级别,我们就可以使用节点的fs 包来操作文件系统。

    这是我的“已完成”中间件(在 typescript 中)...请注意,我正在使用 Vuex 来存储我生成的密钥,这允许我将生成的不记名令牌推送给用户。我还根据令牌到期更新生成文件的修改时间,以便我可以轻松检查令牌何时需要重新生成,从而节省对 oAuth 服务器的过多调用。

    import {Context} from '@nuxt/types';
    
    const getToken = (context: Context) => {
        const axios = require('axios');
    
        return axios.post('/oauth/token', {
            grant_type: 'client_credentials',
            client_id: context.$config.apiClientId,
            client_secret: context.$config.apiClientSecret,
            scope: ''
        }, {
            baseURL: context.$config.apiUrl,
            headers: {'Accept': 'application/json'}
        });
    }
    
    export default function (context: Context) {
    
        // only perform this at the server level.
        if (process.server) {
    
            // set parameters needed.
            const fileName = './.apiToken',
                timestamp = Date.now(),
                fs = require('fs'),
                promise = new Promise(async (resolve, reject) => {
    
    
                    try {
                        // get our stored files timestamps.
                        const data = fs.statSync(fileName);
    
                        // is our file timestamp in the future?
                        if (Date.now() < data.mtimeMs) {
    
                            // resolve our token from our file.
                            resolve(fs.readFileSync(fileName).toString());
                            return;
                        }
                    } catch (err) {
                        // ignore this error (file not found)
                    }
    
                    try {
                        // grab our token from the oAuth server,
                        // we'll reduce the expiry timestamp by 10 mins
                        // to reduce near expiring tokens.
                        const res = await getToken(context),
                            expiryTime = timestamp + (res.data.expires_in - (60 * 10));
    
                        // write our file and sync the times.
                        fs.writeFileSync(fileName, res.data.access_token);
                        fs.utimesSync(fileName, new Date(expiryTime), new Date(expiryTime));
    
                        // resolve our promise with our generated token.
                        resolve(res.data.access_token);
    
                    } catch (err) {
    
                        // ToDo: handle token retrieval failure...
                        console.log(err);
                    }
    
                });
    
            // once our promise is resolved, set it against our store.
            promise.then(
                (token) => context.store.commit('bearerToken/setToken', token),
                // ToDo: better handling of errors...
                (err) => console.log(err)
            );
        }
    }
    

    这使我可以在服务器级别生成一个不记名令牌并将其缓存,然后我可以将其与 SSR 或客户端一起使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-19
      • 1970-01-01
      • 1970-01-01
      • 2020-09-07
      • 2015-11-26
      • 2021-06-18
      相关资源
      最近更新 更多