简体   繁体   English

如何以正确的方式使用passport.js

[英]how to use passport.js in a proper way

I am trying passport library to authenticate api request. 我正在尝试护照库来验证api请求。 To start I have created a NodeJS application with the express framework. 首先,我使用Express框架创建了一个NodeJS应用程序。 The project contains some apis that serve some data. 该项目包含一些提供一些数据的API。 In public folder it contains index.html page having username and password field. 在公用文件夹中,它包含具有用户名和密码字段的index.html页面。

Index.html 的index.html

<form action="/login" method="post">
    <div>
        <label>Username:</label>
        <input type="text" name="name"/>
    </div>
    <div>
        <label>Password:</label>
        <input type="password" name="password"/>
    </div>
    <div>
        <input type="submit" value="Log In"/>
    </div>
</form>

Created a server.ts that create a http server and listen on some port and created apis using express framework. 创建了一个server.ts ,它创建一个http服务器并在某些端口上侦听,并使用express框架创建了api。

Server.ts Server.ts

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("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.userId);
});

// Invoked on every request by passport.session
passport.deserializeUser(function (userId, done) {
        let user = userList.filter(user => userId === user.userId);
        console.log("D-serializer : ", user);
        // only pass if user exist in the session
        if (user.length) {
            done(null, user[0]);
        }
});
// 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)
        if (!user) {
            return done(null, false, { message: 'Incorrect username.' });
        }
        return done(null, user);
    }
));

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

app.get('/done', function (req, res) {
    console.log("Done")
    res.send("done")
})

app.get('/login', function (req, res) {
    console.log("login")
    res.send("login")
})

// http server creation
let server = http.createServer(app);

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

Now when I hit localhost:7000 it opens the login page and when I click submit with username from userList it returns the done otherwise login. 现在,当我点击localhost:7000时,它将打开登录页面,当我单击userList用户名提交时,它将返回已完成的登录。 This is fine. 这可以。

Now every call goes through deserializeUser method. 现在,每个调用都通过deserializeUser方法进行。

The problem is when I call other URLs directly without hitting /login (authenticates the user) they also work fine and return data. 问题是,当我直接调用其他URL而不点击/ login(对用户进行身份验证)时,它们也可以正常工作并返回数据。

I was expecting that if the request is not authenticated all other calls will fail as deserializeUser is intercepting every request but in this case, no passport method is called. 我期望如果请求未通过身份验证,则其他所有调用都将失败,因为deserializeUser会拦截每个请求,但是在这种情况下,不会调用任何护照方法。

Is this how it works? 这是怎么运作的? or I am missing something? 还是我缺少什么?

You need to add a middleware, for check if your user is authenticated: 您需要添加一个中间件,以检查您的用户是否已通过身份验证:

isAuthenticated = (req, res, next) => {
    if (req.isAuthenticated()) {
      //if user is logged in, req.isAuthenticated() will return true 
      return next();
    }
    res.redirect('/login');
};

And you have to use that middleware like that: 而且您必须像这样使用中间件:

//if user not authenticated, he will be redirect on /login
app.get('/done', isAuthenticated, (req, res) => {
    res.send("done")
});

I was missing middleware to authenticate all subsequent requests. 我缺少用于验证所有后续请求的中间件。 So I have created isAuthenticated method (thanks @Sombrero). 所以我创建了isAuthenticated方法(感谢@Sombrero)。

// request interceptor that will check user authentication
private static isAuthenticated = (req, res, next) => {
    console.log("Authenticating :", req.originalUrl)
    if (req.isAuthenticated()) {
        return next();
    }
    res.redirect('/login');
};

and then in every request 然后在每个请求中

app.get('/done', isAuthenticated, (req, res) => {
    res.send("done")
});

but this was tough to use isAuthenticated method in every request. 但这很难在每个请求中使用isAuthenticated方法。 So I created an array of API list that is public and added middleware to intercept every request and updated isAuthenticated method to ignore public apis 因此,我创建了一个公共的API列表数组,并添加了中间件以拦截每个请求,并更新了isAuthenticated方法以忽略公共api

// list of apis for which authentication is not required
private static publicApiList: string[] = ["/login"];

// 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) {
        return next();
    }
    res.redirect('/login');
};

and then used this method as middleware 然后使用这种方法作为中间件

app.use(Server.isAuthenticated)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM