使用cookie保持登录状态步骤详解

这次给大家带来使用cookie保持登录状态步骤详解,使用cookie保持登录状态的注意事项有哪些,下面就是实战案例,一起来看一下。

这次来做一个网站登录的小例子,后面会用到。这个示例会用到Cookie、HTML表单、POST数据体(body)解析。

第一个版本,我们的用户数据就写死在js文件里。第二个版本会引入MongoDB来保存用户数据。

示例准备

1. 使用express创建应用

就下面的命令序列:

express LoginDemocd LoginDemonpm install

登录后复制

2. 登录页面

登录页面的jade模板为login.jade,内容如下:

doctype htmlhtml 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;}p.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(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 setupapp.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 handlerapp.use(function(req, res, next) { var err = new Error('Not Found'); err.status = 404; next(err);});// error handlers// development error handler// will print stacktraceif (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 userapp.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 reallyvar 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”,可以看到下面的效果:

使用cookie保持登录状态步骤详解

折腾几次,登录,退出,再次登录,效果如下:

使用cookie保持登录状态步骤详解

好啦,这就是这个示例的效果。接下来我们来解释一下用到概念和部分代码。

处理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 }));

登录后复制

我们处理/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());

登录后复制

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。

浏览器会解析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,把用户信息放在数据库里。

相信看了本文案例你已经掌握了方法,更多精彩请关注【创想鸟】其它相关文章!

推荐阅读:

Node.js Express安装与使用步骤详解

table表格内对某列内容进行搜索筛选步骤详解

以上就是使用cookie保持登录状态步骤详解的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2759808.html

(0)
上一篇 2025年3月8日 08:42:08
下一篇 2025年3月8日 08:42:17

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • IE下Ajax提交乱码的快速解决方法

    下面我就为大家带来一篇ie下ajax提交乱码的快速解决方法。现在就分享给大家,也给大家做个参考。 哈哈,试了这么多还是encodeURIComponent管用啊!!!! 在汉字的位置加个保护措施:encodeURIComponent(par…

    编程技术 2025年3月8日
    200
  • IE8用ajax访问不能每次都刷新的问题

    这篇文章主要介绍了ie8用ajax访问不能每次都刷新的问题 的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下 AJAX简介 AJAX = Asynchronous JavaScript and XML(异步的 JavaScrip…

    编程技术 2025年3月8日
    200
  • IE8/IE9下Ajax缓存问题

    本文给大家介绍的ie8/ie9下ajax缓存问题的解决办法,非常不错,具有参考借鉴价值,感兴趣的朋友一起看下吧 ajax简介 AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML),…

    编程技术 2025年3月8日
    200
  • IE8下Ajax缓存问题及解决办法

    ajax即“asynchronous javascript and xml”(异步javascript和xml),是指一种创建交互式网页应用的网页开发技术。接下来通过本文给大家介绍ie8下ajax缓存问题及解决办法,一起看下吧 Ajax简介…

    编程技术 2025年3月8日
    200
  • 前端中怎样设置cookie

    这次给大家带来前端中怎样设置cookie,前端中设置cookie的注意事项有哪些,下面就是实战案例,一起来看一下。 cookie 是什么:是一种用来在客户端硬盘上存储信息的手段。 为什么用?:可以用来存储一些信息,实现一些特殊的效果。例如实…

    编程技术 2025年3月8日
    200
  • 通过Ajax手动解决WordPress WP-PostViews不计数的问题

    这篇文章主要介绍了通过ajax手动解决wordpress wp-postviews不计数的问题的相关资料,需要的朋友可以参考下 某个网站开启了Memcached,并安装了WP-PostViews,但是不知道咋滴文章的浏览计数不起作用了。 在…

    2025年3月8日
    200
  • ajax调用中ie缓存问题解决方法

    这篇文章主要介绍了ajax调用中ie缓存问题解决方法,较为详细的分析了ajax调用中ie缓存机制的原理与具体解决方法,具有一定参考借鉴价值,需要的朋友可以参考下 本文实例分析了ajax调用中ie缓存问题解决方法。分享给大家供大家参考,具体如…

    编程技术 2025年3月8日
    200
  • 浅析IE针对Ajax请求结果的缓存问题

    我们通过一个asp.net mvc应用来重现ie针对ajax请求结果的缓存。在一个空asp.net mvc应用中我们定义了如下一个默认的homecontroller,其中包含一个返回当前时间的action方法getcurrenttime。 …

    2025年3月8日
    200
  • 解决ajax跨域请求数据cookie丢失问题

    本文主要是从前端jquery和服务端php为例,分别使用实例解决ajax跨域请求数据cookie丢失问题,推荐给有相同需求的小伙伴们。 前端: 以jquery为例: 需要加入 xhrFields: {            withCred…

    编程技术 2025年3月8日
    200
  • axios怎样解决302状态码问题

    这次给大家带来axios怎样解决302状态码问题,axios解决302状态码问题的注意事项有哪些,下面就是实战案例,一起来看一下。 比如说浏览器打开了一个单页面(SPA)应用,过了一段时间token(或者session)过期了,这个时候页面…

    编程技术 2025年3月8日
    200

发表回复

登录后才能评论