Home >Web Front-end >JS Tutorial >Detailed steps to use cookies to stay logged in
This time I will give you a detailed explanation of the steps to use cookies to stay logged in. What are the precautions for using cookies to stay logged in? The following is a practical case, let's take a look.
This time I will do a small example of website login, which will be used later. This example will use Cookie,HTML form, and POST data body (body) parsing.
In the first version, our user data is written in the js file. The second version will introduce MongoDB to save user data.Example preparation
1. Use express to create an application
The following command sequence:express LoginDemo cd LoginDemo npm install
2. Login page
The jade template of the login page is login.jade, and the content is as follows: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 is placed in the views directory Down. I hard-coded Chinese characters in login.jade. Note that the file is encoded in UTF-8. The end of this template is a dynamic message used to display the login
error message. The msg variable is passed in by the application.
I wrote a simple CSS for the login page, the login.css file, the content is as follows: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; }Please put login.css in the public/stylesheets directory.
3. profile page
After successful login, the configuration page will be displayed. The profile.jade page content:doctype html html head meta(charset='UTF-8') title= title body p #{msg} p #{lastTime} p a(href='/logout') 退出profile.jade is placed in the views directory. Down. The profile page displays a successful login message, also displays the last login time, and finally provides a logout link.
4. App.js changes
I changed app.js so that users can automatically jump to the login page when they visit the website without logging in. The content of the new app.js is as follows: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
I modified users.js and put the authentication, login, logout and other logic in Inside, you must first convert users.js to UTF-8 encoding (sorry, Chinese characters are hard-coded). Content: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;As you can see, I have built in two accounts, admin and foruok. When logging in, I will verify these two accounts and report an error if they are incorrect. Okay, execute "npm start", then open "http://localhost:3000" in the browser, you can see the following effect:
After a few tossing, log in, log out, and log in again, the effect is as follows: Okay, this is the effect of this example. Next we will explain the concepts and some codes used.
Processing POST text data
We use an HTML form in the example to receive the user name and password, when the type of the input element is submit , click it, the browser will organize the data in the form into a certain format, encode it into the body, and POST to the specified server address. The username and password can be found on the server side through the value of the name attribute of theHTML element.
We don’t have to worry about the process of the server parsing the form data. We use express’s body-parser middleware, which will do it for us. We only need to make simple configurations. And express generator has helped us complete these configuration codes, as follows://加载body-parser模块 var bodyParser = require('body-parser'); ... //应用中间件 app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false }));Our code for processing POST requests on the /login path is in users.js, from "router.post('/login'... "Start (line 94, it would be great if markdown could automatically insert line numbers into the code). The code that refers to the user name in the login form is as follows:
var userName = req.body.login_username;Noticed that there is parsing in the express.Request object req Okay body, we use login_username to access the user name. And login_username is the value of the name attribute of our input element in HTML. It is so related. Password is similar.
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,把用户信息放在数据库里。
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
The above is the detailed content of Detailed steps to use cookies to stay logged in. For more information, please follow other related articles on the PHP Chinese website!