美文网首页前端文章翻译
Cookies vs Token,在AngularJS中使用正确

Cookies vs Token,在AngularJS中使用正确

作者: mervynyang | 来源:发表于2016-07-19 12:43 被阅读2362次

    介绍

    对于前端和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

    相关文章

      网友评论

        本文标题:Cookies vs Token,在AngularJS中使用正确

        本文链接:https://www.haomeiwen.com/subject/dszpjttx.html