nodejs-身份認(rèn)證-v1.0.0

cookie

在網(wǎng)站中,http請(qǐng)求是無(wú)狀態(tài)的向拆。也就是說(shuō)即使第一次和服務(wù)器連接后并且登錄成功后亚茬,第二次請(qǐng)求服務(wù)器依然不能知道當(dāng)前請(qǐng)求是哪個(gè)用戶。cookie的出現(xiàn)就是為了解決這個(gè)問(wèn)題亲铡,第一次登錄后服務(wù)器返回一些數(shù)據(jù)(cookie)給瀏覽器才写,然后瀏覽器保存在本地(瀏覽器存)葡兑,當(dāng)該用戶發(fā)送第二次請(qǐng)求的時(shí)候奖蔓,就會(huì)自動(dòng)的把上次請(qǐng)求存儲(chǔ)的cookie數(shù)據(jù)自動(dòng)的攜帶給服務(wù)器,服務(wù)器通過(guò)瀏覽器攜帶的數(shù)據(jù)就能判斷當(dāng)前用戶是哪個(gè)了讹堤。cookie存儲(chǔ)的數(shù)據(jù)量有限吆鹤,不同的瀏覽器有不同的存儲(chǔ)大小,但一般不超過(guò)4KB洲守。因此使用cookie只能存儲(chǔ)一些小量的數(shù)據(jù)疑务。

使用示例
//steps-01:安裝依賴
cnpm install cookie-parser

//steps-02:建服務(wù)器
//cookie-server.js
var express = require('express');
var cookie = require('cookie-parser');
var router = express.Router();

outer.get('/', function (req, res, next) {

    //設(shè)置cookie
    res.cookie('username','zhangsan');
    res.cookie('username','zhangsan',{maxAge:10000}); //有效期以毫秒為單位

    //獲取cookie
    console.log(req.cookies);
    console.log(req.cookies.username);

    //刪除cookie
    res.clearCookie('username');

    res.render('/index', {title: '首頁(yè)'});
});
app.listen(3000);

http://wiki.jikexueyuan.com/project/node-lessons/cookie-session.html

session

用戶登錄成功,服務(wù)端會(huì)創(chuàng)建和保存一個(gè)session(服務(wù)器存)梗醇,并給客戶端一個(gè)sessionId知允。客戶端會(huì)把sessionId保存在cookie中叙谨,每次請(qǐng)求都會(huì)攜帶這個(gè)sessionId温鸽。

//steps-01:創(chuàng)建項(xiàng)目
express -e

//steps-02:安裝依賴
npm install
npm install --save express-session session-file-store

//steps-03:建服務(wù)器
//session-server.js
var express = require('express');
var app = express();
var session = require('express-session');
var FileStore = require('session-file-store')(session);

var identityKey = 'skey';

app.use(session({
    name: identityKey,
    secret: 'chyingp',  // 用來(lái)對(duì)session id相關(guān)的cookie進(jìn)行簽名
    store: new FileStore(),  // 本地存儲(chǔ)session(文本文件,也可以選擇其他store,比如redis的)
    saveUninitialized: false,  // 是否自動(dòng)保存未初始化的會(huì)話涤垫,建議false
    resave: false,  // 是否每次都重新保存會(huì)話姑尺,建議false
    cookie: {
        maxAge: 10 * 1000  // 有效期,單位是毫秒
    }
}));

//steps-04:賬戶數(shù)據(jù)
//users.js
module.exports = {
    items: [
        {name: 'chyingp', password: '123456'}
    ]
};

//steps-05:登陸接口
//session-server.js
var users = require('./users').items;

var findUser = function(name, password){
    return users.find(function(item){
        return item.name === name && item.password === password;
    });
};

// 登錄接口
app.post('/login', function(req, res, next){
    
    var sess = req.session;
    var user = findUser(req.body.name, req.body.password);

    if(user){
        req.session.regenerate(function(err) {
            if(err){
                return res.json({ret_code: 2, ret_msg: '登錄失敗'});                
            }
            
            req.session.loginUser = user.name;
            res.json({ret_code: 0, ret_msg: '登錄成功'});                           
        });
    }else{
        res.json({ret_code: 1, ret_msg: '賬號(hào)或密碼錯(cuò)誤'});
    }   
});

//steps-05:退出接口
//session-server.js
app.get('/logout', function(req, res, next){
    req.session.destroy(function(err) {
        if(err){
            res.json({ret_code: 2, ret_msg: '退出登錄失敗'});
            return;
        }
        
        // req.session.loginUser = null;
        res.clearCookie(identityKey);
        res.redirect('/');
    });
});

//steps-06:判登陸態(tài)
app.get('/', function(req, res, next){
    var sess = req.session;
    var loginUser = sess.loginUser;
    var isLogined = !!loginUser;

    res.render('index', {
        isLogined: isLogined,
        name: loginUser || ''
    });
});

//steps-07:建客戶端

//steps-08:啟客戶端
存在哪里

其中蝠猬,開(kāi)發(fā)環(huán)境存內(nèi)存就好了切蟋。一般的小程序?yàn)榱?code>省事,如果不涉及狀態(tài)共享的問(wèn)題榆芦,用內(nèi)存 session 也沒(méi)問(wèn)題柄粹。但內(nèi)存 session 除了省事之外,沒(méi)有別的好處歧杏。

用 cookie session 的話镰惦,是不用擔(dān)心狀態(tài)共享問(wèn)題的,因?yàn)?session 的 data 不是由服務(wù)器來(lái)保存犬绒,而是保存在用戶瀏覽器端旺入,每次用戶訪問(wèn)時(shí),都會(huì)主動(dòng)帶上他自己的信息凯力。當(dāng)然在這里茵瘾,安全性之類的,只要遵照最佳實(shí)踐來(lái)咐鹤,也是有保證的拗秘。它的弊端是增大了數(shù)據(jù)量傳輸,利端是方便祈惶。

緩存方式是最常用的方式了雕旨,即快,又能共享狀態(tài)捧请。相比 cookie session 來(lái)說(shuō)凡涩,當(dāng) session data 比較大的時(shí)候,可以節(jié)省網(wǎng)絡(luò)傳輸疹蛉。推薦使用活箕。

數(shù)據(jù)庫(kù) session。除非你很熟悉這一塊可款,知道自己要什么育韩,否則還是老老實(shí)實(shí)用緩存吧。

session 的 store 有四個(gè)常用選項(xiàng):1)內(nèi)存 2)cookie 3)緩存 4)數(shù)據(jù)庫(kù)

cookie+session這種模式通常是保存在內(nèi)存中闺鲸,而且服務(wù)從單服務(wù)到多服務(wù)會(huì)面臨的session共享問(wèn)題筋讨,隨著用戶量的增多,開(kāi)銷就會(huì)越大摸恍。而JWT不是這樣的悉罕,只需要服務(wù)端生成token,客戶端保存這個(gè)token,每次請(qǐng)求攜帶這個(gè)token蛮粮,服務(wù)端認(rèn)證解析就可益缎。

JWT(JSON WEB Token)

一種基于JSON的、用于在網(wǎng)絡(luò)上聲明某種主張的令牌(token)然想。JWT通常由三部分組成: 頭信息(header), 消息體(payload)和簽名(signature)莺奔。

頭信息指定了該JWT使用的簽名算法

實(shí)現(xiàn)示例
//steps-01:創(chuàng)建頭部
{
//類型
"typ": "JWT",
//算法
"alg": "HS256"
}
//轉(zhuǎn)成字符:base64

//steps-02:創(chuàng)建荷載
//標(biāo)準(zhǔn)部分(建議但不強(qiáng)制使用)
iss: jwt簽發(fā)者
sub: jwt發(fā)送方
aud: jwt接收方
iat: jwt的簽發(fā)時(shí)間
exp: jwt的過(guò)期時(shí)間
nbf: jwt的可用起點(diǎn)
jti: jwt的唯一標(biāo)識(shí)
//公共部分

//私有部分
{
"name":"Free碼農(nóng)",
"age":"28",
"org":"今日頭條"
}
//轉(zhuǎn)成字符:base64


//steps-03:創(chuàng)建簽證
//頭部
//荷載
//密碼

使用示例
//安裝依賴
{"dependencies": {
    "body-parser": "^1.17.2",
    "express": "^4.15.3",
    "express-jwt": "^5.3.0",
    "jsonwebtoken": "^7.4.1",
    "mongoose": "^4.10.4",
    "morgan": "^1.8.2"
 }}

//配置文件
//config.js
module.exports = {
    'network' : {
    'port':8080
  },    
  'jwtsecret': 'myjwttest',
  'database': '數(shù)據(jù)庫(kù)鏈接或者其他'
};

//數(shù)據(jù)文件
//user.js
var mongoose = require('mongoose');

var Schema = mongoose.Schema;
module.exports = mongoose.model('User', new Schema({ 
    name: String, 
    password: String, 
    admin: Boolean
}));

//建服務(wù)器
/*
技術(shù)注釋://
業(yè)務(wù)注釋://-
*/
var express     = require('express');
var bodyParser  = require('body-parser');
var morgan      = require('morgan');
var mongoose    = require('mongoose');
var jwt    = require('jsonwebtoken'); 
var config = require('./config');
var User   = require('./user');

var app         = express();

//連數(shù)據(jù)庫(kù)
mongoose.connect(config.database); 
//設(shè)全局量
app.set('superSecret', config.jwtsecret);

//使用插件
//析請(qǐng)求體
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
//訪問(wèn)日志
app.use(morgan('dev'));

//路徑處理
app.get('/', function(req, res) {
res.send('JWT 授權(quán)訪問(wèn)的API路徑 http://localhost:' + config.network.port + '/api');
   });
 //存數(shù)據(jù)庫(kù)
app.post('/setup', function(req, res) {
    if(req.body.name && req.body.password){  
        var nick = new User({ 
        name: req.body.name, 
        password: req.body.password,
        admin:req.body.admin||false
          }); 

        nick.save(function(err) {
         if (err) throw err;
        console.log('用戶存儲(chǔ)成功');
        res.json({ success: true });
  });}
  else{
      res.json({ success: false,msg:"錯(cuò)誤參數(shù)" });
  }
});
//獲取令牌
app.post('/authenticate', function(req, res) {
    User.findOne({
        name: req.body.name
     }, function(err, user) {
        if (err) throw err;

        if (!user) {
          res.json({ success: false, message: '用戶賬號(hào)錯(cuò)誤' });
        } else if (user) {
           if (user.password != req.body.password) {
            res.json({ success: false, message: '用戶密碼錯(cuò)誤' });
          } else {
        var token = jwt.sign(user, app.get('superSecret'), {
              expiresIn : 60*60*24// 授權(quán)時(shí)效24小時(shí)
        });
        res.json({
              success: true,
              message: '請(qǐng)使用您的授權(quán)碼',
              token: token
        });
      }   
    }
    });
});

//接口監(jiān)聽(tīng)
app.listen(config.network.port);
console.log('JWT測(cè)試服務(wù)已經(jīng)開(kāi)啟地址: http://localhost:' + config.network.port);

適用場(chǎng)景

JWT適合一次性的命令認(rèn)證,頒發(fā)一個(gè)有效期極短的JWT变泄,即使暴露了危險(xiǎn)也很小令哟,由于每次操作都會(huì)生成新的JWT,因此也沒(méi)必要保存JWT妨蛹,真正實(shí)現(xiàn)無(wú)狀態(tài)屏富。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蛙卤,隨后出現(xiàn)的幾起案子狠半,更是在濱河造成了極大的恐慌,老刑警劉巖颤难,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件神年,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡行嗤,警方通過(guò)查閱死者的電腦和手機(jī)已日,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)栅屏,“玉大人飘千,你說(shuō)我怎么就攤上這事≌祸ǎ” “怎么了护奈?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)甫恩。 經(jīng)常有香客問(wèn)我逆济,道長(zhǎng)酌予,這世上最難降的妖魔是什么磺箕? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮抛虫,結(jié)果婚禮上松靡,老公的妹妹穿的比我還像新娘。我一直安慰自己建椰,他們只是感情好雕欺,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般屠列。 火紅的嫁衣襯著肌膚如雪啦逆。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,730評(píng)論 1 289
  • 那天笛洛,我揣著相機(jī)與錄音夏志,去河邊找鬼。 笑死苛让,一個(gè)胖子當(dāng)著我的面吹牛沟蔑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播狱杰,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼瘦材,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了仿畸?” 一聲冷哼從身側(cè)響起食棕,我...
    開(kāi)封第一講書(shū)人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎错沽,沒(méi)想到半個(gè)月后宣蠕,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡甥捺,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年抢蚀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片镰禾。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡皿曲,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出吴侦,到底是詐尸還是另有隱情屋休,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布备韧,位于F島的核電站劫樟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏织堂。R本人自食惡果不足惜叠艳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望易阳。 院中可真熱鬧附较,春花似錦、人聲如沸潦俺。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至早像,卻和暖如春僻肖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背卢鹦。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工檐涝, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人法挨。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓谁榜,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親凡纳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子窃植,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容