网络埋伏纪事

Node Hero - 8. 使用 Passport.js 进行 Node.js 身份验证

网络埋伏纪事 · 2016-11-21翻译 · 978阅读 原文链接

本教程中将学习如何使用 Passport.js 和 Redis 实现一个本地 Node.js 身份验证策略。

要使用的技术

在一头扎进实际代码之前,我们先看看本章中要用到的新技术。

Passport.js 是什么?

简单、 不花哨的 Node.js 身份验证 - passportjs.org

Passport.js is an authentication middleware for Node.js

Passport 是一个 Node.js 身份认证中间件,我们将把它用于会话管理。

Redis 是什么?

Redis 是一个开源的(BSD 许可)、内存中的数据结构仓库,被用作数据库、缓存和消息代理中间件 - redis.io

我们打算把用户的会话信息存到 Redis 中,而不是在会话过程的内存中。通过这种方式,我们的应用程序会更容易扩展一些。

演示应用

出于演示目的,下面我们创建一个只做如下事情的应用程序:

  • 显示一个登录表单,
  • 显示两个受保护页面:
    • 概述(profile)页面,
    • secured notes

项目结构

在前一章你已经学习了如何组织 Node.js 项目的结构,所以下面我们就开始用所学的知识!

我们打算采用如下结构:

├── app
|   ├── authentication
|   ├── note
|   ├── user
|   ├── index.js
|   └── layout.hbs
├── config
|   └── index.js
├── index.js
└── package.json

正如你所见,我们会围绕着功能来组织文件和目录。我们将有一个用户页,一个备注页,和一些与身份验证相关的功能。

完整的代码下载在 https://github.com/RisingStack/nodehero-authentication。*

Node.js 身份验证流程

我们的目标是实现如下的身份验证流程到我们的应用程序中:

  1. 用户输入姓名和密码
  2. 应用程序检查是否匹配
  3. 如果匹配,就发送一个 Set-Cookie 响应头,用它来验证之后的页面
  4. 当用户从同一域访问页面时,之前设置的 cookie 会被添加到所有的请求中
  5. 用这个 cookie 验证受限制的页面

为设置像这样的身份验证策略,请遵循如下三个步骤:

第一步:设置 Express

我们打算用 Express 作为服务器框架 - 可以通过阅读我们的 Express 教程,来学习更多关于此主题的知识。

// file:app/index.js
const express = require('express')  
const passport = require('passport')  
const session = require('express-session')  
const RedisStore = require('connect-redis')(session)

const app = express()  
app.use(session({  
  store: new RedisStore({
    url: config.redisStore.url
  }),
  secret: config.redisStore.secret,
  resave: false,
  saveUninitialized: false
}))
app.use(passport.initialize())  
app.use(passport.session())

在这里我们做了什么?

首先,我们 require 了所有会话管理所需的依赖。之后,我们从 express-session 模块创建了一个新的实例,用它来存储会话。

为后备存储,我们用了 Redis。但是,你可以使用任何其它数据库,比如 MySQL 或者 MongoDB。

第二步:设置 Node.js Passport

Passport 是使用插件的一个很好的示例库。对于本教程,我们添加 passport-local 模块,该模块让我们可以很容易集成使用用户名和密码的简单本地身份验证策略。

为简单起见,在本例中,我们没有使用第二个后备存储,只用了一个内存中的 user 实例。在真实应用程序中,findUser 会在数据库中查找一个用户。

// file:app/authenticate/init.js
const passport = require('passport')  
const LocalStrategy = require('passport-local').Strategy

const user = {  
  username: 'test-user',
  password: 'test-password',
  id: 1
}

passport.use(new LocalStrategy(  
  function(username, password, done) {
    findUser(username, function (err, user) {
      if (err) {
        return done(err)
      }
      if (!user) {
        return done(null, false)
      }
      if (password !== user.password  ) {
        return done(null, false)
      }
      return done(null, user)
    })
  }
))

一旦 findUser 返回 user 对象,剩下的唯一的事情是比较提供的用户以及真实密码,看看是否匹配。

如果匹配,就让用户进入(通过将用户返回给 passport - return done(null, user));如果不匹配,就返回一个未授权错误(通过什么都不返回给 passport - return done(null))。

第三步:添加受保护的端点

要添加受保护的端点,就得利用 Express 所用的中间件模式。为此,先创建身份验证中间件:

// file:app/authentication/middleware.js
function authenticationMiddleware () {  
  return function (req, res, next) {
    if (req.isAuthenticated()) {
      return next()
    }
    res.redirect('/')
  }
}

这段代码有一个作用,就是如果用户被验证(有正确的 cookies),就调用下一个中间件;否则就重定向到用户登录页面。

用这种方式与把新中间件添加到路由定义一样简单。

// file:app/user/init.js
const passport = require('passport')

app.get('/profile', passport.authenticationMiddleware(), renderProfile)

总结

在本教程中,你已经学习了如何给应用程序添加基础的身份验证。之后,就可以用不同的身份验证策略扩展它,比如 Facebook 或 Twitter。在 http://passportjs.org/ 上可以找到更多策略。

完整的示例代码放在 GitHub 上,你可以看看这里:https://github.com/RisingStack/nodehero-authentication

下一步

下一章主要涉及 Node.js 应用程序的单元测试。你会学习单元测试、测试金字塔、测试替代等概念。

相关文章