Cookies vs Token嘲驾,在AngularJS中使用正確的驗(yàn)證方式

介紹

對于前端和api調(diào)用而言辽故,Cookies和Tokens是兩種服務(wù)器端基本的驗(yàn)證方式。

  • 大多數(shù)人都采用基于cookie驗(yàn)證的方式(你能在這里找到例子)掉弛,在服務(wù)器端使用cookie對用戶對每個請求進(jìn)行身份驗(yàn)證喂走。

  • 另一種新的方式是基于Token驗(yàn)證芋肠。每一次向服務(wù)器發(fā)送請求的時候依賴一個簽名的Token。

Cookies對比Token

這是Cookies和Tokens工作方式的圖解

圖解

使用Token的好處是什么呢?

  • 跨域:cookies + CORS不能很好的在不同的域下使用碘裕。但是Token允許你使用ajax在不同域下調(diào)用任何服務(wù)器帮孔,因?yàn)槟闶褂胔ttp請求頭去傳輸用戶的信息不撑。
  • 無狀態(tài):沒有必要保持session的存儲焕檬,需要傳輸?shù)挠脩粜畔⒍及赥oken里面,其它的狀態(tài)可以存儲在客戶端的local storage或者cookies里兼呵。
  • CDN:在你的應(yīng)用里面腊敲,你可以從CDN里面使用所有的資源(比如javascript, HTML, images等等),你的服務(wù)器端只是一個接口懂昂。
  • 移動優(yōu)先:當(dāng)你在移動端平臺(iOS, Android, Windows 8等)開發(fā)的時候凌彬,你無法與移動終端共享服務(wù)器創(chuàng)建的 session 和 cookie。相比之下勉失,用Token要簡單的多原探。
  • 解耦:你不用綁定一個特定的身份驗(yàn)證的方案咽弦,Token可以在任何地方生成,因此你的api可以在任何地方單獨(dú)調(diào)用驗(yàn)證的方法段审。
  • CSRF(跨站請求偽造):一旦你不再依賴cookie闹蒜,你不需要防止跨站請求寺枉。(通過iframe攻擊你的網(wǎng)站是不可能的,因?yàn)閏ookie是空的绷落,所以不能再使用現(xiàn)有的驗(yàn)證通過的cookie生成post請求)姥闪。
  • 性能:在這里我們不展示任何復(fù)雜的性能標(biāo)準(zhǔn),但是一次網(wǎng)絡(luò)請求的往返(例如砌烁,在數(shù)據(jù)庫查找session)筐喳,花費(fèi)的時間很可能比計(jì)算一個HMACSHA256的token并解析其內(nèi)容的時間更多。
  • 登錄頁面不需要特殊處理:如果你使用Protractor寫你的功能測試函喉,你不需要對你的登陸頁面做特殊處理避归。
  • 基于標(biāo)準(zhǔn):你的api可能采用的是JSON Web Token (JWT)標(biāo)準(zhǔn),這是一個多個后端庫的標(biāo)準(zhǔn)(.NET, Ruby, Java, Python, PHP)梳毙,并且很多公司支持(例如Firebase, Google, Microsoft),舉一個例子撇寞, Firebase允許它們的用戶使用任何的authentication機(jī)制顿天,只要你生成一個JWT,與某些預(yù)定義的屬性蔑担,并簽署了共享密鑰調(diào)用API牌废。

什么是JSON Web Token?JSON Web Token是一個非常輕巧的規(guī)范啤握。這個規(guī)范允許我們使用JWT在用戶和服務(wù)器之間傳遞安全可靠的信息鸟缕。

實(shí)現(xiàn)

假設(shè)你有一個node.js的應(yīng)用,下面你可以找到這個架構(gòu)的組件。

服務(wù)端

讓我們開始安裝express-jwt和jsonwebtoken:

    $ npm install express-jwt jsonwebtoken

定義一個express中間件保護(hù)每一次/api的調(diào)用懂从。

    var expressJwt = require('express-jwt');
    var jwt = require('jsonwebtoken');

    // We are going to protect /api routes with JWT
    app.use('/api', expressJwt({secret: secret}));

    app.use(express.json());
    app.use(express.urlencoded());

這是一個angular的應(yīng)用授段,將會帶上用戶的憑證通過ajax去執(zhí)行post請求。

    app.post('/authenticate', function (req, res) {
      //TODO validate req.body.username and req.body.password
      //if is invalid, return 401
      if (!(req.body.username === 'john.doe' && req.body.password === 'foobar')) {
        res.send(401, 'Wrong user or password');
        return;
      }

      var profile = {
        first_name: 'John',
        last_name: 'Doe',
        email: 'john@doe.com',
        id: 123
      };

      // We are sending the profile inside the token
      var token = jwt.sign(profile, secret, { expiresInMinutes: 60*5 });

      res.json({ token: token });
    });

直接獲取到名字為/api/restricted的資源番甩。注意憑證的驗(yàn)證在expressJwt中間件執(zhí)行侵贵。

    app.get('/api/restricted', function (req, res) {
      console.log('user ' + req.user.email + ' is calling /api/restricted');
      res.json({
        name: 'foo'
      });
    });

AngularJS端

第一步,在客戶端使用AngularJS取得 JWT Token缘薛。為了得到我們需要的用戶憑證窍育,我們得先創(chuàng)建一個表單的視圖,能夠讓用戶輸入用戶名和密碼宴胧。

    <div ng-controller="UserCtrl">
      <span></span>
      <form ng-submit="submit()">
        <input ng-model="user.username" type="text" name="user" placeholder="Username" />
        <input ng-model="user.password" type="password" name="pass" placeholder="Password" />
        <input type="submit" value="Login" />
      </form>
    </div>

一個處理表單提交的controller:

    myApp.controller('UserCtrl', function ($scope, $http, $window) {
      $scope.user = {username: 'john.doe', password: 'foobar'};
      $scope.message = '';
      $scope.submit = function () {
        $http
          .post('/authenticate', $scope.user)
          .success(function (data, status, headers, config) {
            $window.sessionStorage.token = data.token;
            $scope.message = 'Welcome';
          })
          .error(function (data, status, headers, config) {
            // Erase the token if the user fails to log in
            delete $window.sessionStorage.token;

            // Handle login errors here
            $scope.message = 'Error: Invalid user or password';
          });
      };
    });

現(xiàn)在我們JWT保存到sessionStorage中漱抓,如果token設(shè)置了,我們將在每一次使用$http請求的時候設(shè)置Authorization恕齐。作為請求頭的一部分值乞娄,我們將使用Bearer<token>

sessionStorage: 盡管不支持所有的瀏覽器显歧,但是你可以使用polyfill仪或,它是代替cookies的一個比較好的方案。

($cookies, $cookieStore)以及l(fā)ocalStorage:在用戶關(guān)閉瀏覽器標(biāo)簽之后數(shù)據(jù)依然還會存在士骤。

    myApp.factory('authInterceptor', function ($rootScope, $q, $window) {
      return {
        request: function (config) {
          config.headers = config.headers || {};
          if ($window.sessionStorage.token) {
            config.headers.Authorization = 'Bearer ' + $window.sessionStorage.token;
          }
          return config;
        },
        response: function (response) {
          if (response.status === 401) {
            // handle the case where the user is not authenticated
          }
          return response || $q.when(response);
        }
      };
    });

    myApp.config(function ($httpProvider) {
      $httpProvider.interceptors.push('authInterceptor');
    });

然后溶其,我們發(fā)送一個請求到/api/restricted

    $http({url: '/api/restricted', method: 'GET'})
    .success(function (data, status, headers, config) {
      console.log(data.name); // Should log 'foo'
    });

服務(wù)器端控制臺:

    user foo@bar.com is calling /api/restricted

原文: angularjs-authentication-with-cookies-vs-token

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末敦间,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子束铭,更是在濱河造成了極大的恐慌廓块,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件契沫,死亡現(xiàn)場離奇詭異带猴,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)懈万,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門拴清,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人会通,你說我怎么就攤上這事口予。” “怎么了涕侈?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵沪停,是天一觀的道長。 經(jīng)常有香客問我,道長木张,這世上最難降的妖魔是什么众辨? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮舷礼,結(jié)果婚禮上鹃彻,老公的妹妹穿的比我還像新娘。我一直安慰自己妻献,他們只是感情好蛛株,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著旋奢,像睡著了一般泳挥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上至朗,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天屉符,我揣著相機(jī)與錄音,去河邊找鬼锹引。 笑死矗钟,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的嫌变。 我是一名探鬼主播吨艇,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼腾啥!你這毒婦竟也來了东涡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤倘待,失蹤者是張志新(化名)和其女友劉穎疮跑,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凸舵,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡祖娘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了啊奄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片渐苏。...
    茶點(diǎn)故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖菇夸,靈堂內(nèi)的尸體忽然破棺而出琼富,到底是詐尸還是另有隱情,我是刑警寧澤庄新,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布公黑,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏凡蚜。R本人自食惡果不足惜人断,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望朝蜘。 院中可真熱鬧恶迈,春花似錦、人聲如沸谱醇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽副渴。三九已至奈附,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間煮剧,已是汗流浹背斥滤。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留勉盅,地道東北人佑颇。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像草娜,于是被迫代替她去往敵國和親挑胸。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評論 2 355

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