Cookies vs Token,在AngularJS中使用正确的验证方式

介绍

对于前端和api调用而言,Cookies和Tokens是两种服务器端基本的验证方式。

  • 大多数人都采用基于cookie验证的方式(你能在这里找到例子),在服务器端使用cookie对用户对每个请求进行身份验证。

  • 另一种新的方式是基于Token验证。每一次向服务器发送请求的时候依赖一个签名的Token。

Cookies对比Token

这是Cookies和Tokens工作方式的图解

图解

使用Token的好处是什么呢?

  • 跨域:cookies + CORS不能很好的在不同的域下使用。但是Token允许你使用ajax在不同域下调用任何服务器,因为你使用http请求头去传输用户的信息。
  • 无状态:没有必要保持session的存储,需要传输的用户信息都包含在Token里面,其它的状态可以存储在客户端的local storage或者cookies里。
  • CDN:在你的应用里面,你可以从CDN里面使用所有的资源(比如javascript, HTML, images等等),你的服务器端只是一个接口。
  • 移动优先:当你在移动端平台(iOS, Android, Windows 8等)开发的时候,你无法与移动终端共享服务器创建的 session 和 cookie。相比之下,用Token要简单的多。
  • 解耦:你不用绑定一个特定的身份验证的方案,Token可以在任何地方生成,因此你的api可以在任何地方单独调用验证的方法。
  • CSRF(跨站请求伪造):一旦你不再依赖cookie,你不需要防止跨站请求。(通过iframe攻击你的网站是不可能的,因为cookie是空的,所以不能再使用现有的验证通过的cookie生成post请求)。
  • 性能:在这里我们不展示任何复杂的性能标准,但是一次网络请求的往返(例如,在数据库查找session),花费的时间很可能比计算一个HMACSHA256的token并解析其内容的时间更多。
  • 登录页面不需要特殊处理:如果你使用Protractor写你的功能测试,你不需要对你的登陆页面做特殊处理。
  • 基于标准:你的api可能采用的是JSON Web Token (JWT)标准,这是一个多个后端库的标准(.NET, Ruby, Java, Python, PHP),并且很多公司支持(例如Firebase, Google, Microsoft),举一个例子, Firebase允许它们的用户使用任何的authentication机制,只要你生成一个JWT,与某些预定义的属性,并签署了共享密钥调用API。

什么是JSON Web Token?JSON Web Token是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。

实现

假设你有一个node.js的应用,下面你可以找到这个架构的组件。

服务端

让我们开始安装express-jwt和jsonwebtoken:

    $ npm install express-jwt jsonwebtoken

定义一个express中间件保护每一次/api的调用。

    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的应用,将会带上用户的凭证通过ajax去执行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的资源。注意凭证的验证在expressJwt中间件执行。

    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。为了得到我们需要的用户凭证,我们得先创建一个表单的视图,能够让用户输入用户名和密码。

    <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';
          });
      };
    });

现在我们JWT保存到sessionStorage中,如果token设置了,我们将在每一次使用$http请求的时候设置Authorization。作为请求头的一部分值,我们将使用Bearer<token>

sessionStorage: 尽管不支持所有的浏览器,但是你可以使用polyfill,它是代替cookies的一个比较好的方案。

($cookies, $cookieStore)以及localStorage:在用户关闭浏览器标签之后数据依然还会存在。

    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');
    });

然后,我们发送一个请求到/api/restricted

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

服务器端控制台:

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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容