如何用 Express.js 实现 OAuth2 认证

在前后端分离的架构下,前端需要调用后端提供的 API 接口。为了保护用户的个人隐私和数据安全,我们需要在 API 接口中进行身份认证授权。其中,OAuth2 协议成为了当前认证授权的主流方式之一。本文将会介绍如何使用 Express.js 实现 OAuth2 认证。

什么是 OAuth2

OAuth2 是一种授权协议,它允许用户可以通过一个应用程序或者网站来授权第三方应用程序访问它们存储在另外一个服务提供者上的特定资源,而不需要将用户名和密码提供给第三方应用程序。

具体来说,OAuth2 协议中包含以下几个主要的角色:

  1. 资源拥有者(Resource Owner):即用户,拥有能够被访问的资源,例如图片、视频、通讯录等。
  2. 客户端(Client):需要访问用户资源的应用程序。
  3. 授权服务器(Authorization Server):管理资源拥有者对资源的授权,颁发授权码和访问令牌(Access Token)。
  4. 资源服务器(Resource Server):存储资源的服务器,提供 API 接口,接受授权访问请求并响应具体的访问结果。

OAuth2 协议需要客户端先向授权服务器认证,获得访问令牌,然后再使用访问令牌去访问资源服务器。访问令牌需要在授权服务器颁发,并且具有一定的有效期限制。

Express.js 实现 OAuth2 认证

下面我们将以 Express.js 框架为例,介绍如何使用 OAuth2 协议实现认证授权功能。

安装依赖包

首先需要在项目中安装相关的依赖包,例如:

npm install express express-session passport passport-oauth2-client-password

其中,passport 是一个常用的 Node.js 身份验证中间件,passport-oauth2-client-password 是一个专门用于实现带有客户端密码的 OAuth2 认证的插件。

配置路由

在 Express.js 中,我们配置路由以实现 OAuth2 认证的流程。下面是一个示例路由:

const express = require('express');
const session = require('express-session');
const passport = require('passport');
const OAuth2Strategy = require('passport-oauth2-client-password').Strategy;

const router = express.Router();

const CLIENT_ID = process.env.CLIENT_ID; // 客户端 ID
const CLIENT_SECRET = process.env.CLIENT_SECRET; // 客户端密码
const AUTH_URL = process.env.AUTH_URL; // 授权服务器 URL
const TOKEN_URL = process.env.TOKEN_URL; // Token 目标地址

router.use(session({
  secret: 'my-secret',
  resave: true,
  saveUninitialized: true,
}));

router.use(passport.initialize());
router.use(passport.session());

// 配置 OAuth2 Strategy
passport.use(new OAuth2Strategy({
  authorizationURL: AUTH_URL,
  tokenURL: TOKEN_URL,
  clientID: CLIENT_ID,
  clientSecret: CLIENT_SECRET,
  passReqToCallback: true,
}, (req, clientID, clientSecret, done) => {
  // 实现 OAuth2 认证的相应流程
}));

router.get('/login', (req, res, next) => {
  res.render('login', { title: 'OAuth2 登录' });
});

router.get('/auth', passport.authenticate('oauth2'));

router.get('/callback', passport.authenticate('oauth2', {
  failureRedirect: '/login',
}), (req, res, next) => {
  res.redirect('/');
});

module.exports = router;

以上路由中,我们先使用 express-session 中间件来进行路由 session 的设置。然后使用 passport.initialize() 和 passport.session() 中间件来进行 passport 的配置和初始化。

接着,我们使用新建 passport-oauth2-client-password 的 Strategy 实例,来定义 OAuth2 的认证流程。其中,我们需要配置授权服务器的 URL、Token 目标地址、客户端 ID、客户端密码等信息,并通过 passReqToCallback 标志来使 OAuth2Strategy 构造函数可接收请求参数 req。

在路由中,我们通过 get 方法创建 '/login' 路由,用于显示登录页面;通过 '/auth' 路由和 passport.authenticate() 方法创建 OAuth2 认证流程,使用户可以通过本应用程序访问资源服务器的受保护资源。通过 '/callback' 路由来处理 OAuth2 认证回调,并重定向到主页。

编写认证流程

在 OAuth2Strategy 构造函数的回调函数中,我们需要实现 OAuth2 协议的认证流程。下面是该流程的一个简单示例:

passport.use(new OAuth2Strategy({
  authorizationURL: AUTH_URL,
  tokenURL: TOKEN_URL,
  clientID: CLIENT_ID,
  clientSecret: CLIENT_SECRET,
  passReqToCallback: true,
}, (req, clientID, clientSecret, done) => {
  const { username, password } = req.body;

  // 验证客户端密码
  if (CLIENT_ID === clientID && CLIENT_SECRET === clientSecret) {
    // 生成访问令牌
    const accessToken = 'fake-access-token';

    // 将令牌存储到 session 中
    req.session.accessToken = accessToken;

    // 认证流程完成
    done(null, accessToken);
  } else {
    // 认证失败
    done(null, false);
  }
}));

以上示例中,我们从请求参数 req 中获取 username 和 password,通过比对客户端 ID 和密码验证客户端身份。如果身份验证通过,则生成一个访问令牌 accessToken,将它存储到 session 中,并使用 done 函数返回认证成功的状态信息;如果身份验证失败,则使用 done 函数返回认证失败的状态信息。

访问保护资源

在认证完成后,我们可以从 session 中获取访问令牌 accessToken,并将它放入请求头中进行资源访问:

router.get('/protected-resource', (req, res, next) => {
  const { accessToken } = req.session;

  if (!accessToken) {
    return res.redirect('/login');
  }

  res.header('Authorization', `Bearer ${accessToken}`)
     .send('Protected Resource');
});

以上示例中,我们从 session 中获取访问令牌 accessToken,如果访问令牌不存在,则重定向到登录页面。如果访问令牌存在,则将其加入到 Authorization 请求头中,发出带有访问令牌的请求,并返回受保护的资源结果。

总结

本文介绍了如何使用 Express.js 框架实现 OAuth2 认证授权功能。具体可分为三个步骤:安装依赖包、配置路由和编写认证流程。本文的示例代码可以提供参考。OAuth2 认证协议广泛应用于互联网应用程序中,掌握 OAuth2 认证的实现原理,对提高我们的前端开发能力非常有帮助。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65a62636add4f0e0ffed5aef


纠错反馈