Node.js开发入门—使用cookie保持登录
2017-08-07 10:20
746 查看
这次来做一个站点登录的小样例,后面会用到。
这个演示样例会用到Cookie、HTML表单、POST数据体(body)解析。
第一个版本号,我们的用户数据就写死在js文件中。
第二个版本号会引入MongoDB来保存用户数据。
就以下的命令序列:
2. 登录页面
登录页面的jade模板为login.jade,内容例如以下:
login.jade放在views文件夹下。我在login.jade里硬编码了汉字,注意文件用UTF-8编码。
这个模板的最后是一条动态消息,用于显示登录错误信息,msg变量由应用程序传入。
我给login页面写了个简单的CSS。login.css文件,内容例如以下:
请把login.css放在public/stylesheets文件夹下。
3. profile页面
登录成功后会显示配置页面。profile.jade页面内容:
profile.jade放在views文件夹下。profile页面显示一条登录成功的消息。还显示上次登录时间,最后提供了一个退出链接。
4. app.js修改
我修改了app.js。以便用户在没有登录时訪问站点自己主动跳转到login页面。
新的app.js内容例如以下:
5. users.js
我修改了users.js,把认证、登录、登出等逻辑放在里面,首先要把users.js转为UTF-8编码(sorry。硬编码了汉字哈)。内容:
如你所见,我内置了两个账号。admin和foruok,登录时就验证这两个账号,不正确就报错。
好了,运行“npm start”,然后在浏览器里打开“http://localhost:3000”,能够看到以下的效果:
折腾几次,登录,退出。再次登录,效果例如以下:
好啦,这就是这个演示样例的效果。
接下来我们来解释一下用到概念和部分代码。
username与password,在server端,能够通过HTML元素的名字属性的值找出来。
server解析表单数据这一过程,我们不用操心,用了express的body-parser中间件。它会帮我们做这件事。仅仅要做简单的配置就可以。
并且这些配置代码,express generator都帮我们完毕了,例如以下:
我们处理/login路径上的POST请求的代码在users.js里,从“router.post(‘/login’…”開始(94行,要是markdown能自己主动给代码插入行号就好了)。
引用登录表单内的用户名的代码例如以下:
注意到了吧,express.Request对象req内有解析好的body,我们使用login_username来訪问用户名。而login_username就是我们在HTML里的input元素的name属性的值。就这么关联的。password也相似。
HTTP协议本身是无状态的,而应用server往往想保存一些状态,cookie应运而生。由server颁发。通过HTTP头部传给浏览器。浏览器保存到本地。兴许訪问server时再通过HTTP头部传递给server。这样的交互,server就能够在cookie里记录一些用户相关的信息。比方是否登录了。账号了等等,然后就能够依据这些信息做一些动作。比方我们演示样例中的持久登录的实现,就利用了cookie。另一些电子商务站点,实现购物车时也可能用到cookie。
cookie存储的是一些key-value对。
在express里,Request和Response都有cookie相关的方法。Request实例req的cookies属性。保存了解析出的cookie,假设浏览器没发送cookie,那这个cookies对象就是一个空对象。
express有个插件,cookie-parser,能够帮助我们解析cookie。
express生成的app.js已经自己主动为我们配置好了。相关代码:
express的Response对象有一个cookie方法,能够回写给浏览器一个cookie。
以下的代码发送了一个名字叫做“account”的cookie,这个cookie的值是一个对象,对象内有三个属性。
res.cookie()方法原型例如以下:
文档在这里:http://expressjs.com/4x/api.html#res.cookie。
浏览器会解析HTTP头部里的cookie,依据过期时间决定保存策略。当再次訪问server时,浏览器会把cookie带给server。
server使用cookieParser解析后保存在Request对象的cookies属性里。req.cookies本身是一个对象。解析出来的cookie,会被关联到req.cookies的以cookie名字命名的属性上。比方演示样例给cookie起的名字叫account,服务端解析出的cookie,就能够通过req.cookies.account来訪问。注意req.cookies.account本身既可能是简单的值也可能是一个对象。在演示样例中通过res.cookie()发送的名为account的cookie,它的值是一个对象,在这样的情况下,server这边从HTTP请求中解析出的cookie也会被组装成一个对象。所以我们通过req.cookies.account.account就能够拿到浏览器通过cookie发过来的用户名。但假设浏览器没有发送名为“account”的cookie,那req.cookies.account.hash这样的訪问就会抛异常。所以我在代码里使用req.cookies[“account”]这样的方式来检測是否有account这个cookie。
在处理/login路径上的POST请求时。假设登录成功。就把用户名、一个hash值、还有上次登录时间保存在cookie里,并且设置cookie的有效期为60秒。这样在60秒有效期内。浏览器兴许的訪问就会带cookie,服务端代码从cookie里验证用户名和hash值,让用户保持登录状态。当过了60秒。浏览器就不再发送cookie,服务端就觉得须要又一次登录。将用户重定向到login页面。
如今服务端的用户信息就简单的放在js代码里了。非常丑陋,下次我们引入MongoDB,把用户信息放在数据库里。
其他文章:
Node.js开发入门——使用AngularJS内置服务
Node.js开发入门——Angular简单演示样例
Node.js开发入门——使用AngularJS
Node.js开发入门——使用jade模板引擎
Node.js开发入门——Express里的路由和中间件
Node.js开发入门——Express安装与使用
Node.js开发入门——HTTP文件server
Node.js开发入门——HelloWorld再分析
Node.js开发入门——环境搭建与HelloWorld
这个演示样例会用到Cookie、HTML表单、POST数据体(body)解析。
第一个版本号,我们的用户数据就写死在js文件中。
第二个版本号会引入MongoDB来保存用户数据。
演示样例准备
1. 使用express创建应用就以下的命令序列:
express LoginDemo cd LoginDemo npm install
2. 登录页面
登录页面的jade模板为login.jade,内容例如以下:
doctype html html head meta(charset='UTF-8') title 登录 link(rel='stylesheet', href='/stylesheets/login.css') body .form-container p.form-header 登录 form(action='login', method='POST', align='center') table tr td label(for='user') 账号: td input#user(type='text', name='login_username') tr td label(for='pwd') 密码: td input#pwd(type='password', name='login_password') tr td(colspan='2', align='right') input(type='submit', value='登录') p #{msg}
login.jade放在views文件夹下。我在login.jade里硬编码了汉字,注意文件用UTF-8编码。
这个模板的最后是一条动态消息,用于显示登录错误信息,msg变量由应用程序传入。
我给login页面写了个简单的CSS。login.css文件,内容例如以下:
form { margin: 12px; } a { color: #00B7FF; } div.form-container { display: inline-block; border: 6px solid steelblue; width: 280px; border-radius: 10px; margin: 12px; } p.form-header { margin: 0px; font: 24px bold; color: white; background: steelblue; text-align: center; } input[type=submit]{ font: 18px bold; width: 120px; margin-left: 12px; }
请把login.css放在public/stylesheets文件夹下。
3. profile页面
登录成功后会显示配置页面。profile.jade页面内容:
doctype html html head meta(charset='UTF-8') title= title body p #{msg} p #{lastTime} p a(href='/logout') 退出
profile.jade放在views文件夹下。profile页面显示一条登录成功的消息。还显示上次登录时间,最后提供了一个退出链接。
4. app.js修改
我修改了app.js。以便用户在没有登录时訪问站点自己主动跳转到login页面。
新的app.js内容例如以下:
var express = require('express'); var path = require('path'); var favicon = require('serve-favicon'); var logger = require('morgan'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser'); var users = require('./routes/users'); var app = express(); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); // uncomment after placing your favicon in /public //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); app.all('*', users.requireAuthentication); app.use('/', users); // catch 404 and forward to error handler app.use(function(req, res, next) { var err = new Error('Not Found'); err.status = 404; next(err); }); // error handlers // development error handler // will print stacktrace if (app.get('env') === 'development') { app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: err }); }); } // production error handler // no stacktraces leaked to user app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: {} }); }); module.exports = app;
5. users.js
我修改了users.js,把认证、登录、登出等逻辑放在里面,首先要把users.js转为UTF-8编码(sorry。硬编码了汉字哈)。内容:
var express = require('express'); var router = express.Router(); var crypto = require('crypto'); function hashPW(userName, pwd){ var hash = crypto.createHash('md5'); hash.update(userName + pwd); return hash.digest('hex'); } // just for tutorial, it's bad really var userdb = [ { userName: "admin", hash: hashPW("admin", "123456"), last: "" }, { userName: "foruok", hash: hashPW("foruok", "888888"), last: "" } ]; function getLastLoginTime(userName){ for(var i = 0; i < userdb.length; ++i){ var user = userdb[i]; if(userName === user.userName){ return user.last; } } return ""; } function updateLastLoginTime(userName){ for(var i = 0; i < userdb.length; ++i){ var user = userdb[i]; if(userName === user.userName){ user.last = Date().toString(); return; } } } function authenticate(userName, hash){ for(var i = 0; i < userdb.length; ++i){ var user = userdb[i]; if(userName === user.userName){ if(hash === user.hash){ return 0; }else{ return 1; } } } return 2; } function isLogined(req){ if(req.cookies["account"] != null){ var account = req.cookies["account"]; var user = account.account; var hash = account.hash; if(authenticate(user, hash)==0){ console.log(req.cookies.account.account + " had logined."); return true; } } return false; }; router.requireAuthentication = function(req, res, next){ if(req.path == "/login"){ next(); return; } if(req.cookies["account"] != null){ var account = req.cookies["account"]; var user = account.account; var hash = account.hash; if(authenticate(user, hash)==0){ console.log(req.cookies.account.account + " had logined."); next(); return; } } console.log("not login, redirect to /login"); res.redirect('/login? '+Date.now()); }; router.post('/login', function(req, res, next){ var userName = req.body.login_username; var hash = hashPW(userName, req.body.login_password); console.log("login_username - " + userName + " password - " + req.body.login_password + " hash - " + hash); switch(authenticate(userName, hash)){ case 0: //success var lastTime = getLastLoginTime(userName); updateLastLoginTime(userName); console.log("login ok, last - " + lastTime); res.cookie("account", {account: userName, hash: hash, last: lastTime}, {maxAge: 60000}); res.redirect('/profile?'+Date.now()); console.log("after redirect"); break; case 1: //password error console.log("password error"); res.render('login', {msg:"密码错误"}); break; case 2: //user not found console.log("user not found"); res.render('login', {msg:"用户名不存在"}); break; } }); router.get('/login', function(req, res, next){ console.log("cookies:"); console.log(req.cookies); if(isLogined(req)){ res.redirect('/profile?'+Date.now()); }else{ res.render('login'); } }); router.get('/logout', function(req, res, next){ res.clearCookie("account"); res.redirect('/login?'+Date.now()); }); router.get('/profile', function(req, res, next){ res.render('profile',{ msg:"您登录为:"+req.cookies["account"].account, title:"登录成功", lastTime:"上次登录:"+req.cookies["account"].last }); }); module.exports = router;
如你所见,我内置了两个账号。admin和foruok,登录时就验证这两个账号,不正确就报错。
好了,运行“npm start”,然后在浏览器里打开“http://localhost:3000”,能够看到以下的效果:
折腾几次,登录,退出。再次登录,效果例如以下:
好啦,这就是这个演示样例的效果。
接下来我们来解释一下用到概念和部分代码。
处理POST正文数据
我们在演示样例中使用了HTML表单来接收username与password。当input元素的类型为submit时。点击它,浏览器会把表单内的数据按一定的格式组织之后编码进body,POST到指定的server地址。username与password,在server端,能够通过HTML元素的名字属性的值找出来。
server解析表单数据这一过程,我们不用操心,用了express的body-parser中间件。它会帮我们做这件事。仅仅要做简单的配置就可以。
并且这些配置代码,express generator都帮我们完毕了,例如以下:
//载入body-parser模块 var bodyParser = require('body-parser'); ... //应用中间件 app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false }));
我们处理/login路径上的POST请求的代码在users.js里,从“router.post(‘/login’…”開始(94行,要是markdown能自己主动给代码插入行号就好了)。
引用登录表单内的用户名的代码例如以下:
var userName = req.body.login_username;
注意到了吧,express.Request对象req内有解析好的body,我们使用login_username来訪问用户名。而login_username就是我们在HTML里的input元素的name属性的值。就这么关联的。password也相似。
cookie
cookie,按我的理解。就是server发给浏览器的一张门票。要訪问server内容,能够凭票入场,享受某种服务。server能够在门票上记录一些信息。从技术角度讲,想记啥记啥。当浏览器訪问server时,HTTP头部把cookie信息带到server。server解析出来。校验当时记录在cookie里的信息。HTTP协议本身是无状态的,而应用server往往想保存一些状态,cookie应运而生。由server颁发。通过HTTP头部传给浏览器。浏览器保存到本地。兴许訪问server时再通过HTTP头部传递给server。这样的交互,server就能够在cookie里记录一些用户相关的信息。比方是否登录了。账号了等等,然后就能够依据这些信息做一些动作。比方我们演示样例中的持久登录的实现,就利用了cookie。另一些电子商务站点,实现购物车时也可能用到cookie。
cookie存储的是一些key-value对。
在express里,Request和Response都有cookie相关的方法。Request实例req的cookies属性。保存了解析出的cookie,假设浏览器没发送cookie,那这个cookies对象就是一个空对象。
express有个插件,cookie-parser,能够帮助我们解析cookie。
express生成的app.js已经自己主动为我们配置好了。相关代码:
var cookieParser = require('cookie-parser'); ... app.use(cookieParser());
express的Response对象有一个cookie方法,能够回写给浏览器一个cookie。
以下的代码发送了一个名字叫做“account”的cookie,这个cookie的值是一个对象,对象内有三个属性。
res.cookie("account", {account: userName, hash: hash, last: lastTime}, {maxAge: 60000});
res.cookie()方法原型例如以下:
res.cookie(name, value [, options])
文档在这里:http://expressjs.com/4x/api.html#res.cookie。
浏览器会解析HTTP头部里的cookie,依据过期时间决定保存策略。当再次訪问server时,浏览器会把cookie带给server。
server使用cookieParser解析后保存在Request对象的cookies属性里。req.cookies本身是一个对象。解析出来的cookie,会被关联到req.cookies的以cookie名字命名的属性上。比方演示样例给cookie起的名字叫account,服务端解析出的cookie,就能够通过req.cookies.account来訪问。注意req.cookies.account本身既可能是简单的值也可能是一个对象。在演示样例中通过res.cookie()发送的名为account的cookie,它的值是一个对象,在这样的情况下,server这边从HTTP请求中解析出的cookie也会被组装成一个对象。所以我们通过req.cookies.account.account就能够拿到浏览器通过cookie发过来的用户名。但假设浏览器没有发送名为“account”的cookie,那req.cookies.account.hash这样的訪问就会抛异常。所以我在代码里使用req.cookies[“account”]这样的方式来检測是否有account这个cookie。
持久登录
假设用户每次訪问一个须要鉴权的页面都要输入username与password来登录。那就太麻烦了。所以,非常多现代的站点都实现了持久登录。我的演示样例使用cookie简单实现了持久登录。在处理/login路径上的POST请求时。假设登录成功。就把用户名、一个hash值、还有上次登录时间保存在cookie里,并且设置cookie的有效期为60秒。这样在60秒有效期内。浏览器兴许的訪问就会带cookie,服务端代码从cookie里验证用户名和hash值,让用户保持登录状态。当过了60秒。浏览器就不再发送cookie,服务端就觉得须要又一次登录。将用户重定向到login页面。
如今服务端的用户信息就简单的放在js代码里了。非常丑陋,下次我们引入MongoDB,把用户信息放在数据库里。
其他文章:
Node.js开发入门——使用AngularJS内置服务
Node.js开发入门——Angular简单演示样例
Node.js开发入门——使用AngularJS
Node.js开发入门——使用jade模板引擎
Node.js开发入门——Express里的路由和中间件
Node.js开发入门——Express安装与使用
Node.js开发入门——HTTP文件server
Node.js开发入门——HelloWorld再分析
Node.js开发入门——环境搭建与HelloWorld
相关文章推荐
- Node.js开发入门—使用cookie保持登录
- Node.js开发入门(十)——使用cookie保持登录
- Node.js使用cookie保持登录的方法
- Node.js开发入门(九)——使用AngularJS内置服务
- Node.js开发入门—使用AngularJS内置服务
- Node.js开发入门(四)——Express安装与使用
- Node.js开发入门(六)——使用jade模板引擎
- (原创)node.js入门之二:mysql的使用-Mac环境开发
- Node.js开发入门—Express安装与使用
- node.js入门之二:mysql的使用-Mac环境开发
- Node.js开发入门—使用jade模板引擎
- Node.js开发入门—使用对话框ngDialog
- Node.js开发入门—Express安装与使用
- Node.js开发入门—使用http访问外部世界
- Node.js开发入门—Express安装与使用
- 一步一步使用Ext JS MVC与Asp.Net MVC 3开发简单的CMS后台管理系统之登录窗口调试
- Node.js的入门配置开发《视频》