【问题标题】:HapiJS user session managementHapiJS 用户会话管理
【发布时间】:2022-04-14 05:02:12
【问题描述】:

以下代码来自 HapiJS 文档,它描述了如何使用 @hapi/cookie 插件来使用会话和 cookie。

'use strict';

const Hapi = require('@hapi/hapi');


const internals = {};


// Simulate database for demo

internals.users = [
    {
        id: 1,
        name: 'john',
        password: 'password',
    },
];


internals.renderHtml = {
    login: (message) => {

        return `
    <html><head><title>Login page</title></head><body>
    ${message ? '<h3>' + message + '</h3><br></a>' : ''}
    <form method="post" action="/login">
      Username: <input type="text" name="username"><br>
      Password: <input type="password" name="password"><br></a>
    <input type="submit" value="Login"></form>
    </body></html>
      `;
    },
    home: (name) => {

        return `
    <html><head><title>Login page</title></head><body>
    <h3>Welcome ${name}! You are logged in!</h3>
    <form method="get" action="/logout">
      <input type="submit" value="Logout">
    </form>
    </body></html>
      `;
    }
};


internals.server = async function () {

    const server = Hapi.server({ port: 8000 });

    await server.register(require('@hapi/cookie'));

    server.auth.strategy('session', 'cookie', {

        cookie: {
            name: 'sid-example',

            // Don't forget to change it to your own secret password!
            password: 'password-should-be-32-characters',

            // For working via HTTP in localhost
            isSecure: false
        },

        redirectTo: '/login',

        validateFunc: async (request, session) => {

            const account = internals.users.find((user) => (user.id === session.id));

            if (!account) {
                // Must return { valid: false } for invalid cookies
                return { valid: false };
            }

            return { valid: true, credentials: account };
        }
    });

    server.auth.default('session');

    server.route([
        {
            method: 'GET',
            path: '/',
            options: {
                handler: (request, h) => {

                    return internals.renderHtml.home(request.auth.credentials.name);
                }
            }
        },
        {
            method: 'GET',
            path: '/login',
            options: {
                auth: {
                    mode: 'try'
                },
                plugins: {
                    'hapi-auth-cookie': {
                        redirectTo: false
                    }
                },
                handler: async (request, h) => {

                    if (request.auth.isAuthenticated) {
                        return h.redirect('/');
                    }

                    return internals.renderHtml.login();
                }
            }
        },
        {
            method: 'POST',
            path: '/login',
            options: {
                auth: {
                    mode: 'try'
                },
                handler: async (request, h) => {

                    const { username, password } = request.payload;
                    if (!username || !password) {
                        return internals.renderHtml.login('Missing username or password');
                    }

                    // Try to find user with given credentials

                    const account = internals.users.find(
                        (user) => user.name === username && user.password === password
                    );

                    if (!account) {
                        return internals.renderHtml.login('Invalid username or password');
                    }

                    request.cookieAuth.set({ id: account.id });
                    return h.redirect('/');
                }
            }
        },
        {
            method: 'GET',
            path: '/logout',
            options: {
                handler: (request, h) => {

                    request.cookieAuth.clear();
                    return h.redirect('/');
                }
            }
        }
    ]);

    await server.start();
    console.log(`Server started at: ${server.info.uri}`);
};


internals.start = async function() {

    try {
        await internals.server();
    }
    catch (err) {
        console.error(err.stack);
        process.exit(1);
    }
};

internals.start();

我的问题是:在 POST 登录路由中,在用户成功登录后,request.cookieAuth.set({ id: account.id }); 是否将{id:account.id} 保存在内存(缓存)中并将其作为 cookie 发送给客户端?或者这里什么都没有保存? 同样,request.cookieAuth.clear(); 是否从内存和客户端清除会话??

【问题讨论】:

    标签: node.js session hapijs


    【解决方案1】:

    Hapi.js 有自己的内存系统,但您也可以选择使用自定义的东西,例如 Redis 或其他存储。

    我使用 Hapi 的商店,它适用于单个服务器实例。如果您计划拥有一个服务器实例集群,则需要将此类数据的存储卸载到 Redis 等后端存储,否则如果连接不粘,它们将在每个请求时进行负载平衡,并且如果用户点击服务器实例如果没有缓存会话,它将看起来好像用户已注销。使用同步的后端缓存,所有服务器实例共享该缓存数据并保持同步。

    这是我的管理方式。我会为会话密钥生成一个唯一的 UUID,因为用户 ID 非常明显。

    export class AuthCookieData implements IAuthCookieData {
      sid: string
      constructor(data: IAuthCookieData) {
        this.sid = data.sid;
      }
    }
    
    export class AuthCookie {
    
      /**
       *  accepts one parameter: account
       *  account: the user account to register as {username:'username', password:'password', email: 'user@email.com'}
       *  returns: Promise with new account
       */
      static async setCookie(request: Hapi.Request, userProfile: UserProfile): Promise<void> {
          var sid = uuid.v4();
          await request.server.app['cache'].set(sid, userProfile, 0);
          request['cookieAuth'].set(new AuthCookieData({ sid: sid }));
        }
      }
    
      static async sessionCacheFunction(request: Hapi.Request, session: AuthCookieData) {
    
        var userProfile: UserProfile = await request.server.app['cache'].get(session.sid);
        if (!userProfile) {
          return { valid: false };
        } else {
          return { valid: true, credentials: userProfile };
        }
    
      }
    }
    
    
    const handler:Hapi.Lifecycle.Method = async (request: Hapi.Request, h: Hapi.ResponseToolkit) => {
      if (request.auth.isAuthenticated) {
        return request.auth.credentials;
      }
      const userProfile: UserProfile = await UserUtility.login(<ILogin>request.payload);
      if (!userProfile) {
        return Boom.badRequest('Could not authenticate.  Username or password is invalid.');
      }
      AuthCookie.setCookie(request, userProfile);
      return profile;
    };
    
    
    server.auth.strategy('session', 'cookie', {    
      cookie: {
        name: 'sid',
        password: Configuration.auth.password,
        isSecure: false,
        clearInvalid: true
      },
      validateFunc: AuthCookie.sessionCacheFunction
    });  
    

    【讨论】:

      猜你喜欢
      • 2017-09-30
      • 2019-05-25
      • 2022-01-03
      • 1970-01-01
      • 2020-09-20
      • 1970-01-01
      • 1970-01-01
      • 2017-07-17
      • 1970-01-01
      相关资源
      最近更新 更多