Node.js项目实战-构建可扩展的Web应用(第一版): 6 在Node.js应用中使用session和OAuth进行用户认证和授权
2018-01-11 20:11
1041 查看
6.1 使用Express.js中间件实现权限管理
“权限管理”指面向不同的用户开放不同的页面(或接口)权限URL的权限:app.get('/api/*', auth)
6.2 基于token的用户认证
为不同用户赋予不同的权限,所以需要在auto()函数中添加用户认证的流程。最常见的方案是基于cookie或session授权管理。但有些不适用,比如使用REST架构的应用,更有效的方案是在每次请求中都携带token(比较常见的OAuth2.0协议),也可以是E-mail和密码、API密钥、API密码等。
6.3 基于session的用户认证
$ npm install cookie-parser //解析发送的和接收的cookie$ npm install express-session //在每个请求体中暴露res.session对象,并且在内存或持久化存储中session数据
警告:cookie十分不安全,而且存储长度小,推荐的方法是:不去手动操作cookie,只保留session ID字段,由Express.js中间件自动控制
使用Redis或者MongoDB存储session数据,这样既可以保证session数据能够持久化存储也可以实现session数据可跨服务器读取。
6.4 项目实践:为博客增加邮箱和密码登录功能用户认证
为了在博客中实现基于session的用户认证,需要以下步骤:在app.js的配置部分中增加引入和使用session中间件的代码。
实现一个基于session的用户认证中间件,以便我们在多个路由规则之间复用这些代码。
在app.js文件中添加上一步骤中的中间件,以控制非公开页面的访问。
在user.js中实现包含认证过程的登录路由POST /login和登出路由GET /logout
session中间件:在app.js中加入
//定义中间件
app.use(cookieParser('3CCC4ACD-6ED1-4844-9217-82131BDCB239'));
//session需要依赖cookie才能正常工作
app.use(session({secret: '2C44774A-D649-4D44-9535-46E296EF984F'})); 博客中的权限管理:通过检查req.session.admin标记的是否为真。
// 引入依赖
var express = require('express');
var http = require('http');
var path = require('path');
var mongoskin = require('mongoskin');
var dbUrl = process.env.MONGOHQ_URL || 'mongodb://@localhost:27017/blog';
var db = mongoskin.db(dbUrl, {saft: true});
var collections = { articles: db.collection('articles'),
users: db.collection('users')};
// 引入Express.js中间件
var cookieParser = require('cookie-parser');
var session = require('express-session');
var logger = require('morgan');
var errorHandler = require('errorhandler');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
//设置相关配置
var app = express();
app.locals.appTitle = 'blog-express';
//处理请求中的查询
app.use( function(req, res, next) {
if (!collections.articles || !collections.users)
return next(new Error('No collections.'));
req.collections = collections;
return next();
});
// Express.js 配置
//app.set('appName', 'hello-world');
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// Express.js 中间件配置
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser('3CCC4ACD-6ED1-4844-9217-82131BDCB239'));
//session需要依赖cookie才能正常工作
app.use(session({secret: '2C44774A-D649-4D44-9535-46E296EF984F'}));
app.use(methodOverride());
app.use(require('stylus').middleware(__dirname + '/public'));
app.use(express.static(path.join(__dirname, 'public')));
//用户认证中间件
app.use(function(req, res, next) {
if (req.session && req.session.admin)
res.locals.admin = true;
next();
});
//权限管理
var authorize = function(req, res, next) {
if (req.session && req.session.admin)
return next();
else
return res.send(401);
};
if ('development' == app.get('env')) {
app.use(errorHandler());
}
//页面路由
app.get('/', routes.index);
app.get('/login', routes.user.login);
app.post('/login', routes.user.authenticate);
app.get('/logout', routes.use.logout);
app.get('/admin', authorize, routes.article.admin);
app.get('/post', authorize, routes.article.post);
app.post('/post', authorize, routes.article.postArticle);
app.get('/articles/:slug', routes.article.show);
// REST API路由
app.all('/api', authorize);
app.get('/api/article', routes.article.list);
app.port('/api/article', routes.article.add);
app.put('/api/article/:id', routes.article.edit);
app.del('/api/article/:id', routes.article.del);
app.all('*', function(req, res) {
res.send(404);
})
//启动服务
var server = http.createServer(app);
var boot = function() {
server.listen(app.get('port'), function() {
console.log('Express server listening on port' + app.get('port'));
});
}
var shutdown = function() {
server.close();
}
if (require.main === module) {
boot();
} else {
console.info('Running app as a module');
exports.boot = boot;
exports.shutdown = shutdown;
exports.port = app.get('port');
}
//在多核系统上启动cluster多核处理模块(可选)博客中的用户授权:用户的身份是管理员,则设置admin=true。在user.js中的toutes.user.authenticate。
// exports.list = function(req, res) { res.send('respond with a resource'); }; exports.login = function(req, res, next) { res.render('login'); }; exports.logout = function(req, res, next) { req.session.destroy(); res.redirect('/'); }; //用户授权 exports.authenticate = function(req, res, next) { if (!req.body.email || !req.body.password) return res.render('login', {error: 'Please enter your email and password.'}); req.collections.users.findOne({ email: req.body.email, password: req.body.password }, fucntion(error, user) { if (error) return next(error); if (!user) return res.render('login', {error: 'Incorrect email&password combination.'}); req.session.user = user; req.session.admin = user.admin; redds.redirect('/admin'); }) };
6.5 Node.js OAuth组件
OAuth模块可以帮我们计算签名、编码信息、生成HTTP头,最后发送模块。需要完成:发起OAuth握手(即在服务商、用户以及我们的应用之间的一系列请求)、添加回调路由、在session或数据库中存储信息等。可以参考服务商提供的文档,来获取关于接口、方法、参数等内容更详细的说明。$ npm install oauth
6.6 项目实践:为博客增加Twitter OAuth 1.0第三方登录
使用Everyauth实现:自带市面上大部分第三方服务商的OAuth配置。相关文章推荐
- 第6章-在Node.js应用中使用session和OAuth进行用户认证和授权
- Node.js项目实战-构建可扩展的Web应用(第一版):10 为Node.js应用上线做准备
- Node.js项目实战-构建可扩展的Web应用(第一版): 2 使用Express.js 4创建Web应用程序
- Node.js项目实战-构建可扩展的Web应用(第一版):8 使用Express.js和Hapi构建Node.js REST API服务
- Node.js项目实战-构建可扩展的Web应用(第一版): 7 使用ORM类库Mongoose提升你的Node.js数据
- Node.js项目实战-构建可扩展的Web应用(第一版):11 部署Node.js应用
- Node.js项目实战-构建可扩展的Web应用(第一版): 5 MongoDB、Mongoskin特性
- Node.js项目实战-构建可扩展的Web应用(第一版):3 Node.js基于Mocha的测试驱动开发和行为驱动开发
- Node.js项目实战-构建可扩展的Web应用(第一版): 1 安装Node.js及相关要点
- Node.js项目实战-构建可扩展的Web应用(第一版):9 WebSocket,Socket.IO和DerbyJS的实时应用程序
- Node.js项目实战-构建可扩展的Web应用(第一版): 4 模板引擎:Jade和Handlebars
- 在Maven+Spring项目中使用Node.js的Gulp进行前端自动化构建
- 在Maven+Spring项目中使用Node.js的Gulp进行前端自动化构建
- 在Maven+Spring项目中使用Node.js的Gulp进行前端自动化构建
- Node.js项目实践:构建可扩展的Web应用
- 使用express.js框架一步步实现基本应用以及构建可扩展的web应用
- 在Maven+Spring项目中使用Node.js的Gulp进行前端自动化构建
- Spring Boot实战之Filter实现使用JWT进行接口认证 jwt(json web token) 用户发送按照约定,向服务端发送 Header、Payload 和 Signature,
- 使用electron构建跨平台Node.js桌面应用
- 第8章-使用Express.js和Hapi构建Node.js-REST-API服务-8.2.项目依赖