passport.js中deserializeUser方法的好处

时间:2017-11-06 07:41:28

标签: express passport.js

我刚刚开始passport.js。从this article开始,我得到了所有护照方法的流程,并在我的应用程序中实现了相同的工作方式。这是我的server.js,我正在使用passport-local策略。同一服务器上的Angular app和rest API

import { registerControllersFromFolder } from 'giuseppe';
import { MessageManager } from './messaging/MessageManager';
import express = require('express');
import bodyParser = require('body-parser');
import session = require("express-session");
import http = require('http');

// class to hold user info
class User {
    userId: number;
    userName: string;
    constructor(userId: number, userName: string) {
        this.userId = userId;
        this.userName = userName;
    }
}

// server class to create http server
export class Server {
    // list of apis for which authentication is not required
    private static publicApiList: string[] = ["/services/login", "/login", "/favicon.ico"];

    // request interceptor that will check user authentication
    private static isAuthenticated = (req, res, next) => {
        console.log("Authenticating :", req.originalUrl);
        if (req.isAuthenticated() || Server.publicApiList.indexOf(req.originalUrl) > -1) {
            // express routing
            if (req.originalUrl.startsWith("/services")) {
                console.log("Express Routing");
                return next();
            } else { // angular routing -> return index.html
                console.log("Angular Routing");
                return res.sendFile(__dirname + "/public/index.html");
            }
        } else {
            console.log("User not authenticated.")
            res.redirect('/');
        }
    };

    static startServer() {
        let userList: User[] = [new User(1, "Sunil"), new User(2, "Sukhi")];

        let app = express();

        // passport library
        let passport = require('passport');
        let LocalStrategy = require('passport-local').Strategy;

        // middlewares
        app.use(express.static(__dirname + "/public"));
        app.use(bodyParser.json());
        app.use(bodyParser.urlencoded({ extended: false }));

        app.use(session({ resave: false, saveUninitialized: true, secret: "secretKey123!!" }));

        // passport middleware invoked on every request to ensure session contains passport.user object
        app.use(passport.initialize());

        // load seriliazed session user object to req.user 
        app.use(passport.session());

        // Only during the authentication to specify what user information should be stored in the session.
        passport.serializeUser(function (user, done) {
            console.log("Serializer : ", user);
            done(null, user);
        });

        // Invoked on every request by passport.session
        passport.deserializeUser(function (user, done) {
            let validUser = userList.filter(user => user.userId === user.userId)[0];
            console.log("D-serializer : ", validUser);
            done(null,validUser);
        });

        // passport strategy : Only invoked on the route which uses the passport.authenticate middleware.
        passport.use(new LocalStrategy({
            usernameField: 'name',
            passwordField: 'password'
        },
            function (username, password, done) {
                console.log("Strategy : Authenticating if user is valid  :", username)
                let user = userList.filter(user => username === user.userName);
                console.log("Valid user : ", user)
                if (!user) {
                    return done(null, false, { message: 'Incorrect username.' });
                }
                return done(null, user[0]);
            }
        ));

        // intercept request for authentication
        app.use(Server.isAuthenticated);

        app.post('/services/login', passport.authenticate('local', {
            successRedirect: '/profile',
            failureRedirect: '/login'
        }));

        app.get('/services/logout', (req: any, res: any) => {
            req.logout();
            console.log("User Logout");
            res.send("{status:'logout'}")
        });

        // http server creation
        let server = http.createServer(app);
        registerControllersFromFolder({ folderPath: './api' })
            .then(router => {
                app.use(router);
                /* start express server */
            })
            .catch(err => {
                /* error happened during loading and registering */
            });

        server.listen(7000, () => {
            console.log('Up and running on port 7000');
        });
    }
}

exports.startServer = Server.startServer;

// Call a module's exported functions directly from the command line.
require('make-runnable');

当我点击localhost:7000时,它会按照我使用的 index.html 页面提供

app.use(express.static(__dirname + "/public"));

这是一个角度应用程序,因为角度路由login模块将默认加载。我使用了一个检查请求身份验证的中间件,如果是,则基于请求前缀(有角度或快速)路由完成。

对于定义的登录请求,调用本地策略方法,如果这是真的,则调用serializer方法,该方法负责将数据存储在请求会话中。然后调用sucessRedirectfailureRedirect

对于后续请求,因为我使用了检查req.isAuthenticated是否为真的中间件,如果是,则提供请求,否则将用户重定向到登录页面。我知道在每个后续请求deserializeUser方法中都会调用包含serializeUser方法在登录请求中存储的对象的方法。根据文档,这会调用数据库来检查有效用户。

但我很困惑,但是deserializeUser方法的实际用例?我在哪里可以利用这种方法,如果我拦截ecah请求并检查req.isAuthenticted(),那么为什么要用deserializeUser方法调用数据库?>

1 个答案:

答案 0 :(得分:0)

this answer

中所述
  

deserializeUser的第一个参数对应于的关键字   提供给done函数的用户对象(参见1.)。所以你的   借助该键检索整个对象。这里的关键是   用户ID(密钥可以是用户对象的任何密钥,即名称,电子邮件等)。   在deserializeUser中,该键与内存数组匹配/   数据库或任何数据资源。

     

获取的对象作为req.user

附加到请求对象

因此,deserializeUser的好处是您之后的每个请求都有可用的用户对象。

如果您致电deserializeUser,请问为什么需要使用req.isAuthenticated,答案在于req.isAuthenticated的实施:

req.isAuthenticated = function() {
  var property = 'user';
  if (this._passport && this._passport.instance) {
    property = this._passport.instance._userProperty || 'user';
  }

  return (this[property]) ? true : false;
};

对我而言,req.isAuthenticated似乎正在寻找req[user],因此,deserializeUser必须先调用才能正常工作。