Passport.js 简介 #

什么是认证? #

在了解 Passport.js 之前,我们需要先理解"认证"的概念。认证(Authentication)是验证用户身份的过程,确认"你是谁"。

text
┌─────────────────┐
│     用户         │
│  (声称身份)      │
└────────┬────────┘
         │ 提供凭证
         ▼
┌─────────────────┐
│   认证系统       │
│  (验证身份)      │
└────────┬────────┘
         │ 验证结果
         ▼
┌─────────────────┐
│   应用系统       │
│  (授权访问)      │
└─────────────────┘

认证 vs 授权 #

这是两个容易混淆的概念:

概念 英文 回答的问题 示例
认证 Authentication 你是谁? 登录验证身份
授权 Authorization 你能做什么? 权限控制访问资源
text
认证(Authentication):
"你是张三吗?" -> "是的,我是张三"

授权(Authorization):
"张三可以访问管理后台吗?" -> "可以,他是管理员"

什么是 Passport.js? #

Passport.js 是 Node.js 的一个认证中间件,专为 Express 设计。它提供了一套灵活、模块化的认证机制,支持超过 500 种认证策略。

核心定位 #

text
┌─────────────────────────────────────────────────────────────┐
│                         Passport.js                          │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
│  │  模块化策略   │  │  灵活配置    │  │  中间件模式  │         │
│  └─────────────┘  └─────────────┘  └─────────────┘         │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
│  │  会话支持    │  │  无状态支持  │  │  可扩展性    │         │
│  └─────────────┘  └─────────────┘  └─────────────┘         │
└─────────────────────────────────────────────────────────────┘

Passport.js 解决的问题 #

传统认证的痛点 #

在没有 Passport.js 之前,Node.js 认证面临以下问题:

javascript
// 需要自己实现认证逻辑
app.post('/login', (req, res) => {
  const { username, password } = req.body;
  
  // 手动查询用户
  User.findOne({ username }, (err, user) => {
    if (err) return res.status(500).send('Error');
    if (!user) return res.status(401).send('User not found');
    
    // 手动验证密码
    if (user.password !== password) {
      return res.status(401).send('Wrong password');
    }
    
    // 手动设置会话
    req.session.userId = user._id;
    res.send('Login success');
  });
});

// 每个路由都需要重复验证逻辑
app.get('/profile', (req, res) => {
  if (!req.session.userId) {
    return res.status(401).send('Unauthorized');
  }
  // ...
});

Passport.js 的解决方案 #

javascript
// 配置策略
passport.use(new LocalStrategy(
  (username, password, done) => {
    User.findOne({ username }, (err, user) => {
      if (err) return done(err);
      if (!user) return done(null, false);
      if (!user.verifyPassword(password)) return done(null, false);
      return done(null, user);
    });
  }
));

// 简洁的路由
app.post('/login', passport.authenticate('local'), (req, res) => {
  res.send('Login success');
});

// 统一的认证中间件
app.get('/profile', ensureAuthenticated, (req, res) => {
  res.json(req.user);
});

Passport.js 的历史 #

发展历程 #

text
2011年 ─── Passport.js 诞生
    │
    │      Jared Hanson 创建
    │      专为 Express 设计
    │      初始支持本地策略
    │
2012年 ─── OAuth 策略
    │
    │      支持 Facebook、Twitter
    │      OAuth 1.0 和 2.0
    │
2013年 ─── 策略生态
    │
    │      超过 100 种策略
    │      社区贡献活跃
    │
2015年 ─── 企业采用
    │
    │      大量企业使用
    │      成为 Node.js 认证标准
    │
2018年 ─── 策略扩展
    │
    │      超过 300 种策略
    │      JWT 支持完善
    │
2020年 ─── 持续发展
    │
    │      超过 500 种策略
    │      TypeScript 支持
    │
至今   ─── 行业标准
    │
    │      周下载量超过 100 万
    │      Express 认证首选

里程碑版本 #

版本 时间 重要特性
0.1.0 2011 初始发布,本地策略
0.2.0 2012 OAuth 策略支持
0.3.0 2014 会话管理改进
0.4.0 2016 策略接口优化
0.5.0 2020 异步验证支持
0.6.0 2022 现代化重构

为什么选择 Passport.js? #

核心特点 #

1. 模块化设计 #

每种认证策略都是独立的包,按需安装:

bash
# 本地策略
npm install passport-local

# Google OAuth
npm install passport-google-oauth20

# GitHub OAuth
npm install passport-github2

# JWT
npm install passport-jwt

2. 策略模式 #

统一的策略接口,配置灵活:

javascript
// 本地策略
passport.use(new LocalStrategy({
  usernameField: 'email',
  passwordField: 'password'
}, verifyCallback));

// OAuth 策略
passport.use(new GoogleStrategy({
  clientID: GOOGLE_CLIENT_ID,
  clientSecret: GOOGLE_CLIENT_SECRET,
  callbackURL: '/auth/google/callback'
}, verifyCallback));

3. 中间件集成 #

与 Express 无缝集成:

javascript
// 初始化
app.use(passport.initialize());

// 会话支持
app.use(passport.session());

// 路由保护
app.get('/profile', passport.authenticate('local'), handler);

4. 会话支持 #

内置会话管理:

javascript
// 序列化用户
passport.serializeUser((user, done) => {
  done(null, user.id);
});

// 反序列化用户
passport.deserializeUser((id, done) => {
  User.findById(id, (err, user) => {
    done(err, user);
  });
});

5. 无状态支持 #

支持 JWT 等无状态认证:

javascript
// JWT 策略不需要会话
passport.use(new JwtStrategy({
  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
  secretOrKey: 'your-secret'
}, (payload, done) => {
  User.findById(payload.sub, (err, user) => {
    done(err, user);
  });
}));

Passport.js 与其他认证方案对比 #

Passport.js vs 自建认证 #

特性 Passport.js 自建认证
开发效率 ✅ 高 ❌ 低
安全性 ✅ 经过验证 ⚠️ 需自行保证
维护成本 ✅ 低 ❌ 高
功能丰富度 ✅ 500+ 策略 ❌ 需自行开发
学习曲线 ⚠️ 需要学习 ✅ 自己熟悉
定制性 ✅ 可扩展 ✅ 完全控制

Passport.js vs Auth0 #

特性 Passport.js Auth0
部署方式 自托管 云服务
成本 ✅ 免费 ⚠️ 按用户收费
控制权 ✅ 完全控制 ⚠️ 依赖第三方
维护 ⚠️ 需自行维护 ✅ 托管服务
功能 ⚠️ 需自行实现 ✅ 开箱即用
学习曲线 ⚠️ 较陡 ✅ 简单

Passport.js vs Firebase Auth #

特性 Passport.js Firebase Auth
灵活性 ✅ 极高 ⚠️ 有限
数据库 ✅ 任意选择 ⚠️ Firebase
部署 ✅ 自托管 ⚠️ 云服务
成本 ✅ 免费 ⚠️ 按量收费
功能 ⚠️ 需配置 ✅ 开箱即用

Passport.js 的核心概念 #

策略(Strategy) #

策略是 Passport.js 的核心,定义了如何认证用户:

text
┌─────────────────────────────────────────────────────────────┐
│                     Passport 策略                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 本地策略(Local Strategy)                           │   │
│  │ - 用户名/密码认证                                    │   │
│  │ - 适合传统登录表单                                   │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ OAuth 策略                                          │   │
│  │ - Google、Facebook、GitHub 等                       │   │
│  │ - 第三方登录                                        │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ JWT 策略                                            │   │
│  │ - Token 认证                                        │   │
│  │ - 无状态 API                                        │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 其他策略                                            │   │
│  │ - SAML、OpenID、LDAP 等                             │   │
│  │ - 企业级认证                                        │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

验证回调(Verify Callback) #

每个策略都需要一个验证回调函数:

javascript
// 验证回调签名
function verifyCallback(credentials, done) {
  // credentials: 策略提供的凭证
  // done: 完成验证的回调函数
  
  // 成功: done(null, user)
  // 失败: done(null, false)
  // 错误: done(error)
}

// 本地策略示例
passport.use(new LocalStrategy(
  (username, password, done) => {
    User.findOne({ username }, (err, user) => {
      if (err) return done(err);
      if (!user) return done(null, false, { message: '用户不存在' });
      if (!user.validPassword(password)) {
        return done(null, false, { message: '密码错误' });
      }
      return done(null, user);
    });
  }
));

序列化与反序列化 #

用于会话管理:

javascript
// 序列化:用户对象 -> 会话存储
passport.serializeUser((user, done) => {
  done(null, user.id);
});

// 反序列化:会话存储 -> 用户对象
passport.deserializeUser((id, done) => {
  User.findById(id, (err, user) => {
    done(err, user);
  });
});

认证中间件 #

javascript
// 基本用法
app.post('/login', passport.authenticate('local'));

// 自定义选项
app.post('/login', passport.authenticate('local', {
  successRedirect: '/profile',
  failureRedirect: '/login',
  failureFlash: true
}));

// 自定义回调
app.post('/login', (req, res, next) => {
  passport.authenticate('local', (err, user, info) => {
    if (err) return next(err);
    if (!user) return res.status(401).json(info);
    req.logIn(user, (err) => {
      if (err) return next(err);
      return res.json(user);
    });
  })(req, res, next);
});

常用策略一览 #

本地策略 #

javascript
const LocalStrategy = require('passport-local').Strategy;

passport.use(new LocalStrategy(
  (username, password, done) => {
    // 验证逻辑
  }
));

OAuth 2.0 策略 #

javascript
const GoogleStrategy = require('passport-google-oauth20').Strategy;

passport.use(new GoogleStrategy({
  clientID: process.env.GOOGLE_CLIENT_ID,
  clientSecret: process.env.GOOGLE_CLIENT_SECRET,
  callbackURL: '/auth/google/callback'
}, (accessToken, refreshToken, profile, done) => {
  // 验证逻辑
}));

JWT 策略 #

javascript
const JwtStrategy = require('passport-jwt').Strategy;

passport.use(new JwtStrategy({
  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
  secretOrKey: process.env.JWT_SECRET
}, (payload, done) => {
  // 验证逻辑
}));

Passport.js 的应用场景 #

1. 传统 Web 应用 #

text
用户名/密码登录 + Session 管理

适用场景:
- 企业内部系统
- 内容管理系统
- 传统 Web 应用

2. 单页应用(SPA) #

text
JWT 认证 + 无状态 API

适用场景:
- React/Vue/Angular 应用
- 移动 App 后端
- 微服务架构

3. 社交登录 #

text
OAuth 第三方登录

适用场景:
- 消费级应用
- 快速注册登录
- 社交平台集成

4. 企业应用 #

text
SAML/LDAP 集成

适用场景:
- 企业 SSO
- 内部系统
- AD 集成

Passport.js 的优势与局限 #

优势 #

text
✅ 模块化设计
   - 按需引入策略
   - 减少代码体积

✅ 灵活性高
   - 支持多种认证方式
   - 可自由组合

✅ 社区活跃
   - 500+ 策略
   - 丰富的文档和示例

✅ 无侵入性
   - 不强制数据模型
   - 可与任何数据库配合

✅ 可扩展
   - 自定义策略
   - 灵活配置

局限性 #

text
⚠️ 学习曲线
   - 概念较多
   - 配置复杂

⚠️ 文档分散
   - 策略文档各自独立
   - 需要查阅多个来源

⚠️ 会话管理
   - 需要额外配置
   - 生产环境需要 Session Store

⚠️ 错误处理
   - 需要自行处理
   - 错误信息可能不够友好

学习路径 #

text
入门阶段
├── Passport.js 简介(本文)
├── 安装与配置
└── 本地策略

进阶阶段
├── 会话管理
├── OAuth 策略
└── JWT 认证

高级阶段
├── 自定义策略
├── 多策略组合
├── 安全最佳实践
└── 性能优化

下一步 #

现在你已经了解了 Passport.js 的基本概念,接下来学习 安装与配置,开始实际使用 Passport.js!

最后更新:2026-03-28