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

介绍

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

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

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

Cookies对比Token

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

Cookies vs Token,在AngularJS中使用正确的验证方式_第1张图片
图解

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

    

一个处理表单提交的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

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 [email protected] is calling /api/restricted

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

你可能感兴趣的:(Cookies vs Token,在AngularJS中使用正确的验证方式)