使用 Express.js 和 OAuth2 构建安全的 API

使用 Express.js 和 OAuth2 构建安全的 API

在现代网站开发中,API 是不可或缺的一部分。API 提供了一种使得不同应用程序之间进行数据交换和协作的方式。然而,API 的过度使用也会在未经过适当的授权和认证时导致数据泄露和安全漏洞。为了保护 API 的安全性与可靠性,授权和认证是必须的,而 OAuth2 提供了一种有效的解决方案。

OAuth2 是一种流行的授权协议,用于在不泄露用户凭证的情况下授权第三方应用程序访问其资源。OAuth2 分为四个角色:客户端、资源所有者、授权服务器和资源服务器。通过 OAuth2,客户端能够在保护资源所有者的同时获得资源的访问权限。

在本文中,我们将使用 Express.js 和 OAuth2 构建一个安全的 API。我们将基于 oauth2orize 库的实现,该库是一个用于编写 OAuth2 服务器的实用程序库。

安装和配置

在开始构建我们的安全 API 之前,我们需要先安装和配置所需的软件和库:

首先,为了构建我们的 Web 服务器,我们将使用 Express.js。在您的项目目录下,通过以下命令安装:

npm install express

我们还需要安装以下组件:

npm install body-parser cookie-parser debug express-session morgan --save

接下来,我们需要安装 oauth2orize 组件:

npm install oauth2orize --save

当我们得到了所有必需的库后,我们就可以开始设置 OAuth2 验证。在我们的应用程序的主文件中,添加以下代码来设置 OAuth2 验证:

var oauth2orize = require('oauth2orize'), login = require('connect-ensure-login'), passport = require('passport'), crypto = require('crypto');

var server = oauth2orize.createServer();

server.serializeClient(function(client, done) { return done(null, client.id); });

server.deserializeClient(function(id, done) { Client.findById(id, function(err, client) { if (err) { return done(err); } return done(null, client); }); });

server.grant(oauth2orize.grant.code(function(client, redirectURI, user, ares, done) { var code = crypto.randomBytes(16).toString('hex'); var ac = new AuthorizationCode({ code: code, clientId: client.id, redirectUri: redirectURI, userId: user._id }); ac.save(function(err) { if (err) { return done(err); } return done(null, code); }); }));

server.exchange(oauth2orize.exchange.code(function(client, code, redirectURI, done) { AuthorizationCode.findOne({ code: code }, function(err, code) { if (err) { return done(err); } if (code === undefined) { return done(null, false); } if (client.id !== code.clientId) { return done(null, false); } if (redirectURI !== code.redirectUri) { return done(null, false); } // Verify that the user has authorized the application User.findById(code.userId, function(err, user) { if (err) { return done(err); } if (user === undefined) { return done(null, false); } return done(null, user); }); }); }));

使用 OAuth2 验证

现在我们已经完成了 OAuth2 验证的设置,接下来我们就可以使用 OAuth2 验证来保护我们的 API。

首先,我们需要添加一个授权页面,让用户可以选择是否授权我们的应用程序来访问其数据。在我们的应用程序的主文件中,以下代码将创建一个授权端点,它将在用户登录并授权后返回一个授权代码:

app.get('/oauth/authorize', login.ensureLoggedIn(), server.authorize(function(clientID, redirectURI, done) { Client.findOne({ clientID: clientID, redirectURI: redirectURI }, function(err, client) { if (err) { return done(err); } return done(null, client, client.redirectURI); }); }), function(req, res) { res.render('authorize', { transactionID: req.oauth2.transactionID, user: req.user, client: req.oauth2.client }); });

在此示例代码中,我们首先使用 connect-ensure-login 组件来确保用户已登录。接下来,我们调用 server.authorize,它将检查客户端 ID 和重定向 URI 是否与已注册的客户端匹配。如果匹配,它将调用回调函数并返回客户端和重定向 URI。最后,我们将呈现授权模板,以便用户可以选择是否授权我们的应用程序。

现在,我们将创建一个 URL,其中包含客户端 ID、响应类型、重定向 URI 和应用程序状态等信息。该 URL 将访问于上文定义的授权端点,并请求授权。

当用户访问该 URL 时,授权端点将呈现一个授权页面,询问用户是否授权我们的应用程序。如果用户同意授权,则将重定向到我们的应用程序,并附带一个授权代码。

接下来,我们将创建一个交换端点,使用授权代码请求访问令牌。在我们的应用程序中,添加以下代码,实现交换端点:

app.post('/oauth/token', passport.authenticate(['basic', 'oauth2-client-password'], { session: false }), server.token(), server.errorHandler() );

在此示例代码中,我们首先使用 passport.authenticate 检查客户端凭据。接下来,我们使用 server.token 函数,它将在检查授权代码和客户端凭证后返回访问令牌。

现在我们已经建立了 OAuth2 认证,接下来我们将使用 Express.js 构建一个简单的 API,对该 API 进行保护。

构建 API

在我们的应用程序的主文件中,以下代码将创建一个简单的 API,它将返回一些用户数据:

app.get('/api/me', passport.authenticate('bearer', { session: false }), function(req, res) { User.findById(req.user.id, function(err, user) { if (err) { return res.send(err); } res.send(user); }); });

在此示例代码中,我们使用 passport.authenticate 和 bearer 策略来检查访问令牌。如果访问令牌验证成功,则 API 将返回用户数据。

示例应用程序

在 GitHub 上,我们可以找到一个有用的示例应用程序,其中详细说明了如何将 OAuth2 和 Express.js 用于构建安全的 API。跟随 Github 的说明,我们便可以运行本地服务器,并使用 Postman 来演示 API。

总结

通过本文,我们学习了如何使用 Express.js 和 OAuth2 构建安全的 API。我们详细介绍了 OAuth2 的授权过程以及如何在 Express.js 中使用 oauth2orize 库来保护 API。我们还使用示例代码演示了如何在应用程序中实现认证和授权。通过本文中的示例代码,我们可以轻松地构建一个安全的 API,保护用户数据和隐私。

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


纠错
反馈