七个Cookie登入的演示,js使用cookie保持登入的秘籍_node

这一次来做三个网址登入的小例子,后边会用到。那几个示例会用到Cookie、HTML表单、POST数据体深入分析。

这么些示例会用到Cookie、HTML表单、POST数据体(body卡塔尔深入深入分析。
这一个版本选取JSON数据,下个版本采取mysql和mongodb 示例策动

第一个本子,咱们的客户数据就写死在js文件里。第一个版本会引进MongoDB来保存客户数据。

1. 使用express创制应用

就上边包车型客车一声令下类别:

express LoginDemo
cd LoginDemo
cnpm install

示范希图

2. 报到页面

报到页面包车型客车jade模板为views/login.jade,内容如下:

doctype html
html
  head
    meta(charset='UTF-8')
    title Login
    link(rel='stylesheet', href='/stylesheets/login.css')
  body
    .form-container
      p.form-header Login
      form(action='login', method='POST', align='center')
        table
          tr
            td
              label(for='user') User:
            td
              input#user(type='text', name='login_username')
          tr
            td
              label(for='pwd') Password:
            td
              input#pwd(type='password', name='login_password')
          tr
            td(colspan='2', align='right')
              input(type='submit', value='Login')

    //用于显示登录错误信息,msg变量由应用程序传入。          
    p #{msg}  

/public/stylesheets/login.css文本,设置login.html的体裁,内容如下:

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;
}

1. 使用express创建应用

3. profile页面

金沙js8331,报到成功后会突显配置页面,/views/profile.jade页面内容:

doctype html
html
  head
    meta(charset='UTF-8')
    title= title
  body
    p #{msg}
    p #{lastTime}
    p 
      a(href='/logout') 退出

profile页面突显一条登陆成功的新闻,还显得上次登入时间,最终提供了二个脱离链接。

express LoginDemocd LoginDemonpm install

4. app.js改动

app.js,顾客在还未登陆时访谈网址自行跳转到login页面。内容如下:

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;

2. 报到页面

5. users.js

/routes/user.js
把认证、登入、登出等逻辑放在里面,首先要把users.js转为UTF-8编码.内容:

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: "qingcong",
      hash: hashPW("qingcong", "qc123"),
      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;

在users.js中放置了八个账号,admin和qingcong,登陆时就认证那七个账号,不对就报错。前期需求把帐号存款和储蓄到数据库中.

登入页面包车型客车jade模板为login.jade,内容如下:

执行

进行“npm
start”,然后在浏览器里展开“

view-logindemo.png

折腾两遍,登陆,退出,再度登入,效果如下:

view-logindemo-profile.png

好啊,那正是其一示例的效能。接下来大家来解释一下用到概念和部分代码。

拍卖POST正文数据

我们在示范中应用了HTML表单来收取客商名和密码,当input成分的品类为submit时,点击它,浏览器会把表单内的多寡按一定的格式协会未来编码进body,POST到钦点的服务器地址。客户名和密码,在劳务器端,能够透过HTML成分的名字属性的值找寻来。

服务器分析表单数据这一进程,我们不要操心,用了express的body-parser中间件,它会帮大家做那件事,只要做简单的布置就能够。并且那几个布署代码,express
generator都帮我们成功了,如下:

//加载body-parser模块 var bodyParser = require(‘body-parser’卡塔尔国; …
//应用中间件 app.use(bodyParser.json(卡塔尔卡塔尔(قطر‎; app.use(bodyParser.urlencoded({
extended: false }State of Qatar卡塔尔(قطر‎;
大家管理/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,按小编的敞亮,正是服务器发给浏览器的一张门票,要拜见服务器内容,能够凭票上场,享受某种服务。服务器能够在门票上记录一些新闻,从技能角度讲,想记啥记啥。当浏览器访谈服务器时,HTTP尾部把cookie新闻带到服务器,服务器解析出来,校验这个时候记录在cookie里的音信。

HTTP左券本身是无状态的,而应用服务器往往想保留一些气象,cookie应际而生,由服务器颁发,通过HTTP尾部传给浏览器,浏览器保存到地头。后续访问服务器时再经过HTTP底部传递给服务器。那样的相互,服务器就能够在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(State of QatarState of Qatar;
express的Response对象有贰个cookie方法,能够回写给浏览器一个cookie。

上面包车型客车代码发送了叁个名字称为“account”的cookie,这些cookie的值是多少个对象,对象内有多少个个性。

res.cookie(“account”, {account: userName, hash: hash, last: lastTime},
{maxAge: 60000}State of Qatar; res.cookie(卡塔尔方法原型如下:

res.cookie(name, value [, options]卡塔尔国文书档案在那间:http://expressjs.com/4x/api.html#res.cookie。

浏览器会深入分析HTTP尾部里的cookie,依据过期日子决定封存计谋。当再度访谈服务器时,浏览器会把cookie带来服务器。服务器使用cookieParser深入分析后保存在Request对象的cookies属性里,req.cookies本人是三个目的,深入分析出来的cookie,会被波及到req.cookies的以cookie名字命名的属性上。譬如示例给cookie起的名字叫account,服务端分析出的cookie,就能够透过req.cookies.account来访谈。注意req.cookies.account本人既恐怕是差不离的值也只怕是二个对象。在演示中经过res.cookie(卡塔尔发送的名字为account的cookie,它的值是一个对象,在这里种气象下,服务器那边从HTTP乞请中分析出的cookie也会被组装成一个对象,所以我们经过req.cookies.account.account就足以得到浏览器通过cookie发过来的客户名。但要是浏览器未有发送名称为“account”的cookie,那req.cookies.account.hash这种访问就能够抛卓殊,所以本身在代码里应用req.cookies[“account”]这种办法来检查实验是不是有account这一个cookie。

从始至终登陆

假设客商每回访谈一个亟需鉴权的页面都要输入顾客名和密码来报到,那就太费力了。所以,相当多今世的网址都达成了长久登入。作者的亲自过问使用cookie轻巧落成了同心同德登陆。

在拍卖/login路线上的POST央求时,假如登陆成功,就把顾客名、一个hash值、还会有上次登陆时间保存在cookie里,何况安装cookie的保质期为60秒。那样在60秒保藏期内,浏览器后续的走访就能够带cookie,服务端代码从cookie里证实客户名和hash值,让客商保持登入意况。当过了60秒,浏览器就不再发送cookie,服务端就以为需求再行登陆,将用户重定向到login页面。

今昔服务端的客商新闻就差没有多少的放在js代码里了,非常难看,后一次大家引入mongodb,把客商音信放在数据库里。

doctype htmlhtml head meta 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 账号: td input#user(type='text', name='login_username') tr td label 密码: 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 htmlhtml head meta title= title body p #{msg} p #{lastTime} p a 退出

profile.jade放在views目录下。profile页面显示一条登入成功的音讯,还显得上次登入时间,最后提供了多少个脱离链接。

4. app.js改动

本人改造了app.js,以便客商在未有登陆时访谈网址活动跳转到login页面。新的app.js内容如下:

var express = require;var path = require;var favicon = require;var logger = require;var cookieParser = require;var bodyParser = require;var users = require;var app = express();// view engine setupapp.set('views', path.join;app.set('view engine', 'jade');// uncomment after placing your favicon in /public//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));app.use;app.use;app.use(bodyParser.urlencoded;app.use;app.use(express.static(path.join);app.all('*', users.requireAuthentication);app.use;// catch 404 and forward to error handlerapp.use(function { var err = new Error; err.status = 404; next;// error handlers// development error handler// will print stacktraceif  === 'development') { app.use(function { res.status; res.render('error', { message: err.message, error: err }); });}// production error handler// no stacktraces leaked to userapp.use(function { res.status; res.render('error', { message: err.message, error: {} });});module.exports = app;

5. users.js

自个儿改正了users.js,把认证、登陆、登出等逻辑放在中间,首先要把users.js转为UTF-8编码。内容:

var express = require;var router = express.Router();var crypto = require;function hashPW{ var hash = crypto.createHash; hash.update; return hash.digest;}// just for tutorial, it's bad reallyvar userdb = [ { userName: "admin", hash: hashPW, last: "" }, { userName: "foruok", hash: hashPW, last: "" } ];function getLastLoginTime{ for(var i = 0; i < userdb.length; ++i){ var user = userdb[i]; if(userName === user.userName){ return user.last; } } return "";}function updateLastLoginTime{ for(var i = 0; i < userdb.length; ++i){ var user = userdb[i]; if(userName === user.userName){ user.last = Date; return; } }}function authenticate{ for(var i = 0; i < userdb.length; ++i){ var user = userdb[i]; if(userName === user.userName){ if{ return 0; }else{ return 1; } } } return 2;}function isLogined{ if(req.cookies["account"] != null){ var account = req.cookies["account"]; var user = account.account; var hash = account.hash; if(authenticate{ console.log(req.cookies.account.account + " had logined."); return true; } } return false;};router.requireAuthentication = function{ if{ next(); return; } if(req.cookies["account"] != null){ var account = req.cookies["account"]; var user = account.account; var hash = account.hash; if(authenticate{ 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{ 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{ case 0: //success var lastTime = getLastLoginTime; updateLastLoginTime; console.log("login ok, last - " + lastTime); res.cookie("account", {account: userName, hash: hash, last: lastTime}, {maxAge: 60000}); res.redirect('/profile?'+Date.now; console.log; break; case 1: //password error console.log; res.render('login', {msg:"密码错误"}); break; case 2: //user not found console.log; res.render('login', {msg:"用户名不存在"}); break; }});router.get('/login', function{ console.log; console.log; if{ res.redirect('/profile?'+Date.now; }else{ res.render;router.get('/logout', function{ res.clearCookie; res.redirect('/login?'+Date.now;router.get('/profile', function{ res.render('profile',{ msg:"您登录为:"+req.cookies["account"].account, title:"登录成功", lastTime:"上次登录:"+req.cookies["account"].last });});module.exports = router;

如您所见,我内置了五个账号,admin和foruok,登录时就印证那七个账号,不对就报错。

好了,实践“npm
start”,然后在浏览器里张开“

煎熬两次,登陆,退出,再度登入,效果如下:

好啊,那正是以此示例的效率。接下来大家来解释一下用到概念和一些代码。

拍卖POST正文数据

大家在演示中行使了HTML表单来收纳顾客名和密码,当input元素的品种为submit时,点击它,浏览器会把表单内的数额按自然的格式社团现在编码进body,POST到内定的服务器地址。客户名和密码,在劳动器端,能够由此HTML成分的名字属性的值寻觅来。

服务器分析表单数据这一进度,我们绝不操心,用了express的body-parser中间件,它会帮我们做那件事,只要做简单的配置就可以。并且这么些配置代码,express
generator都帮我们做到了,如下:

//加载body-parser模块var bodyParser = require;...//应用中间件app.use;app.use(bodyParser.urlencoded;

大家管理/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,按自个儿的明亮,就是服务器发给浏览器的一张上场券,要拜会服务器内容,能够凭票登台,享受某种服务。服务器能够在门票上记下一些新闻,从工夫角度讲,想记啥记啥。当浏览器访谈服务器时,HTTP尾部把cookie消息带到服务器,服务器分析出来,校验那个时候记录在cookie里的音信。

HTTP左券本身是无状态的,而应用服务器往往想保留一些动静,cookie应时而生,由服务器颁发,通过HTTP尾部传给浏览器,浏览器保存到地头。后续访谈服务器时再经过HTTP底部传递给服务器。这样的彼此,服务器就足以在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;...app.use;

express的Response对象有四个cookie方法,能够回写给浏览器三个cookie。

上边包车型地铁代码发送了四个名字称为“account”的cookie,那些cookie的值是叁个对象,对象内有七个属性。

复制代码 代码如下:res.cookie(“account”,
{account: userName, hash: hash, last: lastTime}, {maxAge: 60000}State of Qatar;

res.cookie(卡塔尔方法原型如下:

res.cookie(name, value [, options])

文书档案在这里间:

浏览器会深入解析HTTP尾部里的cookie,根据过期时光线调节制封存战略。当再度做客服务器时,浏览器会把cookie带给服务器。服务器使用cookieParser拆解深入分析后保存在Request对象的cookies属性里,req.cookies自己是三个对象,深入分析出来的cookie,会被提到到req.cookies的以cookie名字命名的性情上。比方示例给cookie起的名字叫account,服务端深入分析出的cookie,就足以由此req.cookies.account来做客。注意req.cookies.account自身既大概是轻松的值也可能是二个目的。在演示中经过res.cookie(卡塔尔发送的名称为account的cookie,它的值是多少个指标,在此种景色下,服务器那边从HTTP乞求中剖判出的cookie也会被组装成一个目的,所以我们经过req.cookies.account.account就足以得到浏览器通过cookie发过来的客商名。但纵然浏览器未有发送名称叫“account”的cookie,那req.cookies.account.hash这种访谈就能够抛相当,所以自个儿在代码里使用req.cookies[“account”]这种方法来检查测验是还是不是有account这么些cookie。

有始有终登入

假定客户每回访问贰个亟待鉴权的页面都要输入客商名和密码来报到,那就太难为了。所以,相当多今世的网址都贯彻了悠久登入。我的上行下效使用cookie轻巧达成了坚持到底登陆。

在拍卖/login路线上的POST须要时,借使登入成功,就把客商名、二个hash值、还会有上次登陆时间保存在cookie里,而且安装cookie的保藏期为60秒。那样在60秒保藏期内,浏览器后续的拜见就能够带cookie,服务端代码从cookie里证实客户名和hash值,让客户保持登入情形。当过了60秒,浏览器就不再发送cookie,服务端就以为必要重新登入,将客商重定向到login页面。

今天服务端的顾客消息就总结的坐落于js代码里了,超丑,下一次我们引进MongoDB,把客商音讯放在数据Curry。

以上便是本文的全部内容,希望对大家的上学抱有利于,也愿意大家多多指教脚本之家。

发表评论

电子邮件地址不会被公开。 必填项已用*标注