Nodejs express的OAuth2认证流程
Nodejs express的OAuth2认证流程
我想大家都知道oauth2是通过access_token去限制访问api的接口,通过时间过期规则要重新登录才能访问接口,但是oauth2里面有提供一个叫refresh access_token的方法,这样就保证能自动获取最新的access_token以免过期,具体原理我也不多讲了,下面是要做的步骤: 首先大家先要在index.js中定义一些配置:
global.__basename = __dirname; #定义文件夹的目录
require('coffee-script'); #加载coffeescript的语法,如果不需要可以不用写
process.env.TZ = 'PRC'; #设置时间
app.coffee要添加以下代码:
cors = require './middlewares/cors'
oauth = require './middlewares/oauth'
app.use cors
app.use oauth.oauth()
app.use oauth.login()
我们然后我们要新建一个oauth.coffee放在middlewares中,里面要用第三方的oauth2-provider npm install oauth2-provider
,然后还要依次加载一些必要的包
OAuth2Provider = require('oauth2-provider').OAuth2Provider
config = require __basename + '/config/config'
mysql = require __basename + '/connections/mysql/test' #此处为你的mysql链接句柄
mohair = require 'mohair'
async = require 'async'
_ = require 'underscore'
makeExtraData = require __basename + '/helpers/oauth/extra_data'
makeExtraData require的实际上是oauth的用户验证.
在’/helpers/oauth/中新建立一个extra_data.coffee在里面写下以下代码
mhoair = require 'mohair'
mysql = require __basename + '/connections/mysql/test' #此处为你的mysql链接句柄
#链接users表,拿到该users所属的群主
module.exports = (userId, fn) ->
mohair
.connect(mysql)
.table('users')
.select('group_id')
.where(id: userId)
.findOne (err, result) ->
fn err, groupId: result.group_id
然后回到middlewares/oauth.coffee中开始认证
module.exports = oauth = new OAuth2Provider
crypt_key: config.oauth.cryptKey
sign_key: config.oauth.signKey
在此需要检查用户登录状态,并且实现页面跳转
oauth.on 'enforce_login', (req, res, authorizeUrl, next) ->
return next req.session.userId if req.session.userId
res.redirect '/oauth/login?next=' + encodeURIComponent authorizeUrl
现在应该实现验证了.
oauth.on 'authorize_form', (req, res, clientId, authorizeUrl) ->
async.auto
permission: (fn) ->
mohair
.connect(mysql)
.table('user_role_relations urr')
.join('left join roles r on urr.role_id = r.id')
.where('urr.user_id': req.session.userId)
.where('r.product_id': clientId)
.exists fn
,
(err, results) ->
res.locals.authorizeUrl = authorizeUrl
if results.permission
#res.render 至成功页面
else
#res.render 至失败页面
在创建access_token的时候检查用户是否存在
oauth.on 'create_access_token', (userId, clientId, next) ->
makeExtraData userId, (err, result) ->
next result
oauth.on 'save_access_token', (userId, clientId, accessToken) ->
#然后保存access_token,在此你可以进行其他操作
最后,开始创建access_token啦.config.oauth.accessTokenTTL 为access_token的过期时间
oauth.on 'access_token', (req, info, next) ->
#在此判断access_token是否过期
if info.grant_date.getTime() + config.oauth.accessTokenTTL > Date.now()
req.session.userId = info.user_id
req.session.groupId = info.extra_data?.groupId
async.auto
role: (callback) ->
mohair
.connect(mysql)
.table('user_role_relations urr')
.join('left join roles r on urr.role_id = r.id')
.select('urr.role_id as role_id')
.where('urr.user_id': info.user_id)
.findOne callback
permission: ['role', (callback, results) ->
return callback null, [] unless results.role
mohair
.connect(mysql)
.table('role_permission_relations rpr')
.join('left join permissions p on rpr.permission_id = p.id')
.select('p.constant')
.where('rpr.role_id': results.role.role_id)
.exec callback
]
,
(err, results) ->
next err if err
req.session.permissions = _.pluck results.permission, 'constant'
next()
else
req.session.error = 'access_token timeout'
next()
我想上面的代码大家应该都能看懂吧,先判断access_token是否过期,然后将【用户、群主、及用户权限存入至session中,如果权限不存在,返回就是空,也就是该用户没有权限】
接下来,我们应该开始添加url接口,实现oauth2认证了就应该在router.coffee写下如下代码:
app = require './app'
# OAuth
app.use '/oauth', require './lib/oauth'
新建/lib/oauth/index.coffee,在这里可以实现登录获取access_token及登出等操作.
express = require 'express'
mysql = require __basename + '/connections/mysql/test'
mohair = require 'mohair'
config = require __basename + '/config/config'
querystring = require 'querystring'
oauth = require __basename + '/middlewares/oauth'
restrict = require __basename + '/middlewares/restrict'
makeExtraData = require __basename + '/helpers/oauth/extra_data'
module.exports = app = express()
#在此处进行登录验证,成功后进行页面跳转,并设置session
app.post '/login', (req, res) ->
{email, password} = req.body
mohair
.connect(mysql)
.table('users')
.select('id')
.where(email: email)
.where(password: password)
.findOne (err, result) ->
if result
req.session.userId = result.id
else
req.session.error = 'Invalid User'
res.redirect req.body.next
登出方法
app.get '/logout', (req, res) ->
req.session = null
res.redirect '/oauth/authorize?' + querystring.stringify req.query
刷新access_token
app.get '/refresh_token', restrict(), (req, res) ->
makeExtraData req.session.userId, (err, extraData) ->
result = oauth.generateAccessToken req.session.userId, null, extraData
res.json access_token: result.access_token
登出和刷新所提供的两个方法都是oauth2本身提供的方法
middlewares/restrict.coffee代码如下:
_ = require 'underscore'
module.exports = (permission) ->
(req, res, next) ->
unless req.query.access_token
return res.json 400, error: "require access_token"
if req.session.error
return res.json 400, error: req.session.error
if permission and ! _.contains req.session.permissions, permission
return res.json 400, error: 'You dont have the permission'
next()
如果有权限就会调用next()实现跳转了,在调用login的时候要传一个next的参数,这个是登录成功后跳转的页面
在routes里面,大家可以通过restrict去判断该用户是否具备某routes权限
Users = require './user'
app.get '/users', restrict('list'), Users.index
里面的list是该route的权限,是跟数据库test中的permissions表中的constant对应,该表结构如下:
Nodejs Express 的 OAuth2 认证流程
OAuth2 是一种授权框架,用于授予客户端(如Web应用)对HTTP服务(资源服务器)上的受保护资源进行有限访问的权限。在 Node.js 中使用 Express 框架实现 OAuth2 认证流程通常涉及以下几个步骤:
1. 安装依赖
首先,你需要安装 oauth2-server
库来处理 OAuth2 流程。你也可以使用其他库,比如 passport-oauth2
,但这里我们使用 oauth2-server
作为示例。
npm install oauth2-server
2. 配置 OAuth2 Server
在你的项目中定义全局变量并加载必要的模块。
// index.js
global.__basename = __dirname;
require('coffee-script');
process.env.TZ = 'PRC';
3. 设置中间件
在 app.js
或 app.coffee
中设置 CORS 和 OAuth 中间件。
// app.js
const cors = require('./middlewares/cors');
const oauth = require('./middlewares/oauth');
app.use(cors);
app.use(oauth.oauth());
app.use(oauth.login());
4. 创建 OAuth2 Provider
创建一个 OAuth2Provider
实例,并定义必要的回调函数。
// middlewares/oauth.js
const OAuth2Provider = require('oauth2-server').OAuth2Server;
const config = require(__dirname + '/../config/config');
const mysql = require(__dirname + '/../connections/mysql/test');
module.exports = new OAuth2Provider({
model: {
// 实现必要的模型方法
},
grants: ['password'],
debug: true,
});
5. 用户认证逻辑
实现用户认证逻辑,包括登录、登出和刷新 token。
// lib/oauth/index.js
const express = require('express');
const mysql = require(__dirname + '/../connections/mysql/test');
const oauth = require(__dirname + '/../middlewares/oauth');
const app = express();
app.post('/login', (req, res) => {
const { email, password } = req.body;
// 在这里查询数据库以验证用户
mysql.query(
'SELECT * FROM users WHERE email = ? AND password = ?',
[email, password],
(err, result) => {
if (result.length > 0) {
req.session.userId = result[0].id;
res.redirect(req.body.next);
} else {
req.session.error = 'Invalid User';
res.redirect('/');
}
}
);
});
app.get('/logout', (req, res) => {
req.session = null;
res.redirect('/oauth/authorize?' + querystring.stringify(req.query));
});
app.get('/refresh_token', (req, res) => {
const { user_id } = req.session;
const extraData = {}; // 根据需求生成额外数据
const result = oauth.generateAccessToken(user_id, null, extraData);
res.json({ access_token: result.access_token });
});
module.exports = app;
6. 权限控制
实现权限控制中间件,确保只有具有特定权限的用户才能访问某些路由。
// middlewares/restrict.js
module.exports = (permission) => {
return (req, res, next) => {
if (!req.query.access_token) {
return res.status(400).json({ error: 'require access_token' });
}
if (req.session.error) {
return res.status(400).json({ error: req.session.error });
}
if (permission && !req.session.permissions.includes(permission)) {
return res.status(400).json({ error: 'You don\'t have the permission' });
}
next();
};
};
7. 路由配置
根据权限配置路由。
// routes.js
const Users = require('./user');
const restrict = require('./middlewares/restrict');
app.get('/users', restrict('list'), Users.index);
通过以上步骤,你可以在 Node.js 中使用 Express 实现 OAuth2 认证流程。每个步骤都提供了详细的代码示例和解释,帮助你理解整个流程。
这个是coffeescript
的语法,就是ruby on rails
语言的语法,呵呵.
因为整个过程包括登录,认证以及验证,所以可能有点点复杂.
你在index.js中加入这个代码就可以用coffeescript的语法了.
require('coffee-script')
长文帮顶~
coffee 也挺不错的, 但是总是充当人肉编译器, 想编译完是啥样子, 还是写 js 吧
OAuth2认证是一种常用的授权机制,允许客户端安全地访问服务器资源,而无需暴露用户的凭证。在Node.js中使用Express框架结合OAuth2-Provider库来实现OAuth2认证流程包括几个关键步骤:
-
安装依赖:首先确保安装了
oauth2-provider
和其它必需的依赖。npm install oauth2-provider express mohair mysql2
-
初始化OAuth2 Provider:在中间件文件中初始化
OAuth2Provider
并配置加密密钥。const OAuth2Provider = require('oauth2-provider').OAuth2Provider; const config = require(__dirname + '/config/config'); module.exports = oauth = new OAuth2Provider({ crypt_key: config.oauth.cryptKey, sign_key: config.oauth.signKey });
-
处理登录请求:创建登录接口,验证用户凭据并生成会话。
app.post('/login', (req, res) => { const { email, password } = req.body; // 假设的MySQL查询验证用户 db.query("SELECT * FROM users WHERE email=? AND password=?", [email, password], (err, result) => { if (result.length) { req.session.userId = result[0].id; res.redirect(req.body.next); } else { req.session.error = 'Invalid credentials'; res.redirect('/login'); } }); });
-
处理OAuth请求:创建OAuth端点用于获取令牌。
app.post('/oauth/token', oauth.token());
-
保护API路由:使用中间件验证访问令牌。
const restrict = require('./middlewares/restrict'); app.get('/protected', restrict(['read']), (req, res) => { res.send('This is a protected route!'); });
-
实现令牌刷新:创建刷新令牌的端点。
app.get('/refresh_token', restrict(), (req, res) => { const refreshToken = req.query.refresh_token; oauth.refreshToken(refreshToken).then((response) => { res.json({ access_token: response.accessToken }); }).catch((error) => { res.status(401).json({ error: 'Failed to refresh token' }); }); });
以上步骤演示了一个基本的OAuth2认证流程。实际应用中需要考虑更多的细节,比如错误处理、安全性加固、以及与特定数据库交互时的性能优化。