`

Express Cookie & Session

 
阅读更多

原创转载请注明出处:http://agilestyle.iteye.com/blog/2355955

 

cookie 和 session

HTTP 是一个无状态协议,所以客户端每次发出请求时,下一次请求无法得知上一次请求所包含的状态数据,如何能把一个用户的状态数据关联起来呢?

比如在天猫的某个页面中,你进行了登陆操作。当你跳转到商品页时,服务端如何知道你是已经登陆的状态?

 

cookie


 

Express Cookie

https://www.npmjs.com/package/cookie-parser

var express = require('express');
var cookieParser = require('cookie-parser');

var app = express();
app.listen(3000);

app.use(cookieParser());

app.get('/', function(req, res) {
	if (req.cookies.isVisit) {
		console.log(req.cookies);
		res.send("Welcome Again");
	} else {
		res.cookie('isVisit', 1, {
			maxAge: 60 * 1000
		});

		res.send("Welcome First");
	}
});

 

Session

 

Express Session

https://www.npmjs.com/package/express-session

var express = require('express');
var session = require('express-session');

var app = express();
app.listen(3000);

app.use(session({
  secret: 'recommend to use 128 bytes random string',
  cookie: {
    maxAge: 60 * 1000
  }
}));

app.get('/', function(req, res) {
  if (req.session.isVisit) {
    req.session.isVisit++;
    res.send('you viewed this page ' + req.session.isVisit + ' times');
  } else {
    req.session.isVisit = 1;
    res.send("welcome first");
    console.log(req.session);
  }
});

 

Demo

使用cookie-parser和express-session实现一个用户持久登录的Demo

 

Project Directory


 

src

package.json

{
  "name": "node-cookie-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.16.0",
    "cookie-parser": "^1.4.3",
    "crypto-js": "^3.1.9-1",
    "ejs": "^2.5.5",
    "express": "^4.14.1",
    "express-session": "^1.15.0",
    "install": "^0.8.7",
    "npm": "^4.1.2",
    "parseurl": "^1.3.1",
    "path": "^0.12.7"
  }
}

 

index.js

var express = require('express');
var ejs = require('ejs');
var path = require('path');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var session = require('express-session');

var routes = require('./routes/routes');

var app = express();

app.engine('.html', ejs.__express);

app.set("port", process.env.PORT || 3000);
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "html");

app.use(bodyParser.urlencoded({
	extended: false
}));
app.use(bodyParser.json());
app.use(cookieParser());

app.use(session({
	secret: 'keyboard cat',
	resave: false,
	saveUninitialized: true,
	cookie: {
		maxAge: 60 * 1000
	}
}));

app.use(routes);

app.listen(app.get('port'), function() {
	console.log('Server started on port ' + app.get('port'));
});

Note:

将ejs模板后缀.ejs改为.html


使用body-parser、cookie-parser和express-session


 

routes.js

var express = require('express');
var CryptoJS = require("crypto-js");
var parseurl = require('parseurl');

var router = express.Router();

// mock-up user info start
var userDB = [{
	username: 'admin',
	password: md5('123456'),
	lastLogin: ''
}, {
	username: 'node',
	password: md5('123456'),
	lastLogin: ''
}, {
	username: 'express',
	password: md5('123456'),
	lastLogin: ''
}];
// mock-up user info end

function md5(password) {
	return CryptoJS.MD5(password).toString();
}

function getLastLoginTime(username) {
	for (var i in userDB) {
		if (username === userDB[i].username) {
			return userDB[i].lastLogin;
		}
	}

	return "";
}

function updateLastLoginTime(username) {
	for (var i in userDB) {
		if (username === userDB[i].username) {
			userDB[i].lastLogin = Date().toString();
		}
	}
}

function authenticateUserInfoFromDB(username, password) {
	for (var i in userDB) {
		if (username === userDB[i].username) {
			if (password === userDB[i].password) {
				return 1;
			} else {
				return 0;
			}
		}
	}

	return -1;
}

function isAuthenticated(req, res) {
	if (typeof req.cookies.account === 'undefined' || req.cookies.account === null) {
		return false;
	}

	if (req.cookies.account !== null && req.cookies.account !== '') {
		var account = req.cookies.account;

		if (authenticateUserInfoFromDB(account.username, account.password) === 1) {
			console.log(req.cookies.account.username + " logged in.");
			return true;
		}
	}

	return false;
}

function ensureAuthenticated(req, res, next) {
	req.session.url = parseurl(req).pathname;
	console.log(req.session.url);

	if(isAuthenticated(req, res)) {
		next();
	} else {
		res.redirect('/login?' + Date.now());
	}
}

// router.use(function (req, res, next) {
//     res.locals.msg = req.msg;
//     next();
// });

router.get('/', function(req, res) {
	res.render('login');
});

router.get('/login', function(req, res) {
	if (isAuthenticated(req, res)) {
		res.redirect('/welcome?' + Date.now());
	} else {
		res.render('login');
	}
});

router.post('/login', function(req, res, next) {
	var username = req.body.username;
	var password = md5(req.body.password);

	var url = req.session.url;
	console.log('in login url ' + url);

	var result = authenticateUserInfoFromDB(username, password);

	if (result === 1) {
		var lastLogin = getLastLoginTime(username);
		updateLastLoginTime(username);

		res.cookie('account', {
			username: username,
			password: password,
			lastLogin: lastLogin
		}, {
			maxAge: 60 * 1000
		});

		console.log('in login ' + req.session.url);

		if (typeof url !== 'undefined' && url !== null && url !== '') {
			res.redirect(url + '?' + Date.now());
		} else {
			res.redirect('/welcome?' + Date.now());
		}

	} else if (result === 0) {
		res.render('login', {
			msg: 'password incorrect'
		});
	} else if (result === -1) {
		res.render('login', {
			msg: 'username not exist'
		});
	}
});

router.get('/logout', function(req, res, next) {
	res.clearCookie('account');
	req.session.url = '';

	res.redirect('/login?' + Date.now());
});

router.get('/welcome', ensureAuthenticated, function(req, res, next) {
	res.render('welcome', {
		msg: 'username: ' + req.cookies.account.username,
		title: 'Login Success',
		lastLogin: 'lastLogin: ' + (req.cookies.account.lastLogin === '' ? 'N/A' : req.cookies.account.lastLogin)
	});
});

router.get('/profile', ensureAuthenticated, function(req, res, next) {
	res.render('profile');
});

router.get('/messages', ensureAuthenticated, function(req, res, next) {
	res.render('messages');
});

module.exports = router;

Note:

这里仅仅是为了Demo,所以不操作数据库,仅仅mockup一下


使用md5加密password、获取最后登录时间、更新最后登录时间


验证输入的用户名和密码是否有效,1:有效 0:密码错 -1:用户不存在


 这里采用将username和password存如一个名为account的cookie,将未登录前的输入的url存入session用于页面跳转


login的get和post路由表,其中post请求中将username和password存入名为account的cookie,时间为1分钟


welcome、profile、messages的get路由表,其中ensureAuthenticated起到了一个拦截器的作用


 

_footer.html

</body>
</html>

 

_header.html

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Login</title>
	<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
	<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css">
	<script type="text/javascript" src="//code.jquery.com/jquery-3.1.1.min.js"></script>
	<script type="text/javascript" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>

 

 login.html

<% include _header.html %>
	<div class="container">
		<div class="row">
			<div class="col-sm-8 col-sm-offset-2">
				<div class="page-header">
					<div class="alert alert-info" role="alert">
						<h4>This demo shows how to use cookie-parser and express-session</h4>
						<ul>
							<li>
								<a href="https://www.npmjs.com/package/cookie-parser" class="alert-link">cookie-parser</a>
							</li>
							<li>
								<a href="https://www.npmjs.com/package/express-session" class="alert-link">express-session</a>
							</li>
						</ul>
					</div>
					<% if(locals.msg) {%>
						<div class="alert alert-warning" role="alert">
							<p><%= locals.msg %></p>
						</div>
					<% } %>
				</div>

				<div class="panel panel-default">
					<div class="panel-heading">
						<h3 class="panel-title">Log in</h3>
					</div>
					<div class="panel-body">
						<form action="/login"  method="post" class="form-horizontal">
							<div class="form-group">
								<label class="col-sm-4 control-label" for="username">Username</label>
								<div class="col-sm-5">
									<input type="text" class="form-control" id="username" name="username"
										placeholder="Username" required="required" autofocus="autofocus">
								</div>	
							</div>
								
							<div class="form-group">
								<label class="col-sm-4 control-label" for="password">Password</label>
								<div class="col-sm-5">
									<input type="password" class="form-control" id="password" name="password"
										placeholder="Password" required="required">
								</div>	
							</div>

							<div class="form-group">
								<div class="col-sm-5 col-sm-offset-4">
									<input type="submit" value="Log in" class="btn btn-primary">
								</div>
							</div>
						</form>
					</div>
				</div>
			</div>
		</div>
	</div>
<% include _footer.html %>

Note:

如果不想在html页面中使用locals.msg


 可以在routes.js中定义如下方法,之后在页面上可以直接使用 msg 即可取到值,但是这仅限于login.html页面,此msg是req.locals.msg, 与余下几个页面的 msg 无关

router.use(function (req, res, next) {
     res.locals.msg = req.msg;
     next();
});

 

messages.html

<% include _header.html %>
	<div class="container">
		<div class="row">
			<div class="col-sm-8 col-sm-offset-2">
				<div class="page-header">
					<div class="alert" role="alert">
						<ul class="nav nav-pills">
						  <li role="presentation" class="active"><a href="/welcome">Welcome</a></li>
						  <li role="presentation"><a href="/profile">Profile</a></li>
						  <li role="presentation"><a href="/messages">Messages</a></li>
						  <li role="presentation"><a href="/logout">Logout</a></li>
						</ul>
					</div>

					<div class="alert alert-success" role="alert">
						<h2>In Messages Page</h2>
					</div>
				</div>
			</div>
		</div>
	</div>
<% include _footer.html %>

 

profile.html

<% include _header.html %>
	<div class="container">
		<div class="row">
			<div class="col-sm-8 col-sm-offset-2">
				<div class="page-header">
					<div class="alert" role="alert">
						<ul class="nav nav-pills">
						  <li role="presentation" class="active"><a href="/welcome">Welcome</a></li>
						  <li role="presentation"><a href="/profile">Profile</a></li>
						  <li role="presentation"><a href="/messages">Messages</a></li>
						  <li role="presentation"><a href="/logout">Logout</a></li>
						</ul>
					</div>

					<div class="alert alert-success" role="alert">
						<h2>In Profle Page</h2>
					</div>
				</div>
			</div>
		</div>
	</div>
<% include _footer.html %>

 

welcome.html

<% include _header.html %>
	<div class="container">
		<div class="row">
			<div class="col-sm-8 col-sm-offset-2">
				<div class="page-header">
					<div class="alert" role="alert">
						<ul class="nav nav-pills">
						  <li role="presentation" class="active"><a href="/welcome">Welcome</a></li>
						  <li role="presentation"><a href="/profile">Profile</a></li>
						  <li role="presentation"><a href="/messages">Messages</a></li>
						  <li role="presentation"><a href="/logout">Logout</a></li>
						</ul>
					</div>

					<div class="alert alert-success" role="alert">
						<h2><%= title %></h2>
						<h4><%= msg %></h4>
						<h4><%= lastLogin %></h4>
					</div>
				</div>
			</div>
		</div>
	</div>
<% include _footer.html %>

 

Test

http://localhost:3000/


password incorrect


 

login success


Note:

默认登录成功话会直接跳转welcome页面


查看welcome的cookie信息


 

等1分钟后,在点击Profile Tab,会提示重新登录,重新输入用户名和密码之后,会直接跳转到Profle页面


 

Message页面


 

Reference

http://expressjs.com/en/4x/api.html

https://www.npmjs.com/package/cookie-parser

https://www.npmjs.com/package/express-session

https://github.com/alsotang/node-lessons/tree/master/lesson16

 

 

 

 

  • 大小: 117 KB
  • 大小: 149.4 KB
  • 大小: 3.8 KB
  • 大小: 27.2 KB
  • 大小: 17.6 KB
  • 大小: 28.4 KB
  • 大小: 30.1 KB
  • 大小: 17.4 KB
  • 大小: 46.1 KB
  • 大小: 53.8 KB
  • 大小: 32.5 KB
  • 大小: 7.8 KB
  • 大小: 44.4 KB
  • 大小: 39.3 KB
  • 大小: 38.9 KB
  • 大小: 20.3 KB
  • 大小: 23.4 KB
  • 大小: 85.5 KB
  • 大小: 83.3 KB
分享到:
评论

相关推荐

    Express-Session源码分析

    Express-Session的核心功能在于为每个用户创建一个唯一的session ID,这个ID存储在客户端的cookie中,而相应的session数据则存储在服务器端。这种设计既保证了安全性,又避免了大量数据存储在客户端。当用户发起新的...

    express如何使用session与cookie的方法

    本文将详细介绍在Express框架中如何使用session和cookie。 首先,cookie是由服务器发送到客户端(浏览器)的一小块数据,存储在用户的本地设备上。服务器可以通过检查客户端发送回的cookie来识别用户身份。在...

    cookieAndsession.zip

    例如,`express-session`库提供了简单易用的Session管理接口,而`cookie-parser`库则可以帮助解析和操作Cookie。 1. **安装库**:首先,需要通过npm安装这两个库: ``` npm install express-session cookie-...

    cookie-session:基于cookie的简单会话中间件

    cookie-session不需要服务器端的任何数据库/资源​​,尽管会话的总数据不能超过浏览器的最大cookie大小。 cookie-session可以简化某些负载平衡方案。 cookie-session可用于存储“轻量”会话,并包含一个标识符以...

    前端开源库-express-mysql-session

    【标题】"前端开源库-express-mysql-session"是一个专为Express.js框架设计的会话管理中间件,它允许开发者将用户的会话数据存储在MySQL数据库中,而非传统的内存或文件系统。Express.js是Node.js平台上广泛使用的...

    express express-session的使用小结

    首先,`express-session`的基本功能是管理会话,通过在客户端的cookie中存储一个唯一的Session ID来实现。这样,每次客户端请求时,服务器可以通过这个ID查找并恢复相应的会话数据,这些数据实际上是存储在服务器端...

    nestjs-cookie-session:NestJS的惯用Cookie会话模块。 建立在`cookie-session` top之上

    nestjs-cookie-session NestJS的惯用Cookie会话模块。 建立在之上 :smiling_face_with_sunglasses: 例 注册模块: // app.module.ts import { Module } from '@nestjs/common' ; import { ...

    nodejs+mongodb+express+ejs+connect-mongo

    例如,使用`body-parser`解析请求体,`cookie-parser`处理cookie,`session`管理用户会话。定义路由处理GET、POST等请求,返回EJS模板或JSON数据。 4. **EJS**: 在EJS模板中,你可以用`&lt;% %&gt;`包裹JavaScript代码,`...

    详解node.js平台下Express的session与cookie模块包的配置

    `express-session` 是一个中间件,用于处理和存储session数据,而`cookie-parser` 则用于解析客户端发送的cookie信息。通过以下命令可以在项目中安装它们: ```bash npm install express-session --save-dev npm ...

    cookie-session, 基于简单cookie的会话中间件.zip

    cookie-session, 基于简单cookie的会话中间件 cookie会话 基于简单cookie的会话中间件。用户会话可以通过 Cookies 以两种主要方式存储: 在服务器上或者在客户端上。 这个模块在cookie中存储会话数据,而像 express...

    express-socket.io-session, socket.io 共享基于cookie的会话中间件.zip

    express-socket.io-session, socket.io 共享基于cookie的会话中间件 express-socket.io-sessionsocket.io 共享基于cookie的会话中间件。 使用英镑表示的&gt; 4.0.0 和英镑&gt; 1.0.0,不支持向后兼容。帮助我注意错误或者...

    svelte-kit-cookie-session::hammer_and_pick:SvelteKit的加密“无状态” cookie会话

    这与express-session有所不同,在express-session中,cookie包含一个会话ID,然后将其用于在服务器端映射数据。 默认情况下,Cookie具有 :alarm_clock: 有效期为7天,可通过[ expires ]设置,以days number单位。 ...

    实现session身份认证机制

    在这个主题中,我们将深入探讨如何使用Node.js的Express框架以及cookie来实现session身份认证。 首先,让我们理解一下基本概念: 1. **Session**: 一个session是服务器存储的关于用户的一段数据,通常包括用户ID等...

    详解nodejs express下使用redis管理session

    实现请求身份验证的方式很多,其中一种广泛接受的方式是使用服务器端产生的Session ID结合浏览器的Cookie实现对Session的管理,一般来说包括以下4个步骤: 1.服务器端的产生Session ID 2.服务器端和客户端存储...

    express如何解决ajax跨域访问session失效问题详解

    本文将详细探讨如何解决Express中ajax跨域访问时session失效的问题。 首先,我们需要理解为何在跨域请求中session会失效。在HTTP协议中,由于同源策略的限制,浏览器不会在跨域请求中发送cookies,而session通常是...

Global site tag (gtag.js) - Google Analytics