最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當前位置: 首頁 - 科技 - 知識百科 - 正文

使用cookie保持登錄狀態(tài)步驟詳解

來源:懂視網(wǎng) 責編:小采 時間:2020-11-27 19:48:03
文檔

使用cookie保持登錄狀態(tài)步驟詳解

使用cookie保持登錄狀態(tài)步驟詳解:這次給大家?guī)硎褂胏ookie保持登錄狀態(tài)步驟詳解,使用cookie保持登錄狀態(tài)的注意事項有哪些,下面就是實戰(zhàn)案例,一起來看一下。這次來做一個網(wǎng)站登錄的小例子,后面會用到。這個示例會用到Cookie、HTML表單、POST數(shù)據(jù)體(body)解析。第一個版本,我們的用戶數(shù)據(jù)
推薦度:
導讀使用cookie保持登錄狀態(tài)步驟詳解:這次給大家?guī)硎褂胏ookie保持登錄狀態(tài)步驟詳解,使用cookie保持登錄狀態(tài)的注意事項有哪些,下面就是實戰(zhàn)案例,一起來看一下。這次來做一個網(wǎng)站登錄的小例子,后面會用到。這個示例會用到Cookie、HTML表單、POST數(shù)據(jù)體(body)解析。第一個版本,我們的用戶數(shù)據(jù)
這次給大家?guī)硎褂胏ookie保持登錄狀態(tài)步驟詳解,使用cookie保持登錄狀態(tài)的注意事項有哪些,下面就是實戰(zhàn)案例,一起來看一下。

這次來做一個網(wǎng)站登錄的小例子,后面會用到。這個示例會用到Cookie、HTML表單、POST數(shù)據(jù)體(body)解析。

第一個版本,我們的用戶數(shù)據(jù)就寫死在js文件里。第二個版本會引入MongoDB來保存用戶數(shù)據(jù)。

示例準備

1. 使用express創(chuàng)建應用

就下面的命令序列:

express LoginDemo
cd LoginDemo
npm install

2. 登錄頁面

登錄頁面的jade模板為login.jade,內(nèi)容如下:

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編碼。

這個模板的最后是一條動態(tài)消息,用于顯示登錄錯誤信息,msg變量由應用程序傳入。

我給login頁面寫了個簡單的CSS,login.css文件,內(nèi)容如下:

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頁面內(nèi)容:

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,以便用戶在沒有登錄時訪問網(wǎng)站自動跳轉(zhuǎn)到login頁面。新的app.js內(nèi)容如下:

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轉(zhuǎn)為UTF-8編碼(sorry,硬編碼了漢字哈)。內(nèi)容:

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;

如你所見,我內(nèi)置了兩個賬號,admin和foruok,登錄時就驗證這兩個賬號,不對就報錯。

好了,執(zhí)行“npm start”,然后在瀏覽器里打開“http://localhost:3000”,可以看到下面的效果:

折騰幾次,登錄,退出,再次登錄,效果如下:

好啦,這就是這個示例的效果。接下來我們來解釋一下用到概念和部分代碼。

處理POST正文數(shù)據(jù)

我們在示例中使用了HTML表單來接收用戶名和密碼,當input元素的類型為submit時,點擊它,瀏覽器會把表單內(nèi)的數(shù)據(jù)按一定的格式組織之后編碼進body,POST到指定的服務器地址。用戶名和密碼,在服務器端,可以通過HTML元素的名字屬性的值找出來。

服務器解析表單數(shù)據(jù)這一過程,我們不用擔心,用了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能自動給代碼插入行號就好了)。引用登錄表單內(nèi)的用戶名的代碼如下:

var userName = req.body.login_username;

注意到了吧,express.Request對象req內(nèi)有解析好的body,我們使用login_username來訪問用戶名。而login_username就是我們在HTML里的input元素的name屬性的值。就這么關聯(lián)的。password也類似。

cookie

cookie,按我的理解,就是服務器發(fā)給瀏覽器的一張門票,要訪問服務器內(nèi)容,可以憑票入場,享受某種服務。服務器可以在門票上記錄一些信息,從技術角度講,想記啥記啥。當瀏覽器訪問服務器時,HTTP頭部把cookie信息帶到服務器,服務器解析出來,校驗當時記錄在cookie里的信息。

HTTP協(xié)議本身是無狀態(tài)的,而應用服務器往往想保存一些狀態(tài),cookie應運而生,由服務器頒發(fā),通過HTTP頭部傳給瀏覽器,瀏覽器保存到本地。后續(xù)訪問服務器時再通過HTTP頭部傳遞給服務器。這樣的交互,服務器就可以在cookie里記錄一些用戶相關的信息,比如是否登錄了,賬號了等等,然后就可以根據(jù)這些信息做一些動作,比如我們示例中的持久登錄的實現(xiàn),就利用了cookie。還有一些電子商務網(wǎng)站,實現(xiàn)購物車時也可能用到cookie。

cookie存儲的是一些key-value對。在express里,Request和Response都有cookie相關的方法。Request實例req的cookies屬性,保存了解析出的cookie,如果瀏覽器沒發(fā)送cookie,那這個cookies對象就是一個空對象。

express有個插件,cookie-parser,可以幫助我們解析cookie。express生成的app.js已經(jīng)自動為我們配置好了。相關代碼:

var cookieParser = require('cookie-parser');
...
app.use(cookieParser());

express的Response對象有一個cookie方法,可以回寫給瀏覽器一個cookie。

下面的代碼發(fā)送了一個名字叫做“account”的cookie,這個cookie的值是一個對象,對象內(nèi)有三個屬性。

代碼如下:

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,根據(jù)過期時間決定保存策略。當再次訪問服務器時,瀏覽器會把cookie帶給服務器。服務器使用cookieParser解析后保存在Request對象的cookies屬性里,req.cookies本身是一個對象,解析出來的cookie,會被關聯(lián)到req.cookies的以cookie名字命名的屬性上。比如示例給cookie起的名字叫account,服務端解析出的cookie,就可以通過req.cookies.account來訪問。注意req.cookies.account本身既可能是簡單的值也可能是一個對象。在示例中通過res.cookie()發(fā)送的名為account的cookie,它的值是一個對象,在這種情況下,服務器這邊從HTTP請求中解析出的cookie也會被組裝成一個對象,所以我們通過req.cookies.account.account就可以拿到瀏覽器通過cookie發(fā)過來的用戶名。但如果瀏覽器沒有發(fā)送名為“account”的cookie,那req.cookies.account.hash這種訪問就會拋異常,所以我在代碼里使用req.cookies[“account”]這種方式來檢測是否有account這個cookie。

持久登錄

如果用戶每次訪問一個需要鑒權(quán)的頁面都要輸入用戶名和密碼來登錄,那就太麻煩了。所以,很多現(xiàn)代的網(wǎng)站都實現(xiàn)了持久登錄。我的示例使用cookie簡單實現(xiàn)了持久登錄。

在處理/login路徑上的POST請求時,如果登錄成功,就把用戶名、一個hash值、還有上次登錄時間保存在cookie里,并且設置cookie的有效期為60秒。這樣在60秒有效期內(nèi),瀏覽器后續(xù)的訪問就會帶cookie,服務端代碼從cookie里驗證用戶名和hash值,讓用戶保持登錄狀態(tài)。當過了60秒,瀏覽器就不再發(fā)送cookie,服務端就認為需要重新登錄,將用戶重定向到login頁面。

現(xiàn)在服務端的用戶信息就簡單的放在js代碼里了,非常丑陋,下次我們引入MongoDB,把用戶信息放在數(shù)據(jù)庫里。

相信看了本文案例你已經(jīng)掌握了方法,更多精彩請關注Gxl網(wǎng)其它相關文章!

推薦閱讀:

Node.js Express安裝與使用步驟詳解

table表格內(nèi)對某列內(nèi)容進行搜索篩選步驟詳解

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文檔

使用cookie保持登錄狀態(tài)步驟詳解

使用cookie保持登錄狀態(tài)步驟詳解:這次給大家?guī)硎褂胏ookie保持登錄狀態(tài)步驟詳解,使用cookie保持登錄狀態(tài)的注意事項有哪些,下面就是實戰(zhàn)案例,一起來看一下。這次來做一個網(wǎng)站登錄的小例子,后面會用到。這個示例會用到Cookie、HTML表單、POST數(shù)據(jù)體(body)解析。第一個版本,我們的用戶數(shù)據(jù)
推薦度:
標簽: 登錄 步驟 登陸
  • 熱門焦點

最新推薦

猜你喜歡

熱門推薦

專題
Top