饼干牌。ng获取正确授权

作者好diao啊,我不懂的他全都懂了。

Cookies vs Tokens. Getting auth right with Angular.JS

基本上服务端有两种不同的方式来实现对前端和 API 的授权:

  • 用的最多的是,Cookie-Based 授权(你可以看),用服务端的 cookie 来验证每个请求
  • 比较新的是,Token-Based 授权,依赖于发送到服务端的请求中的授权令牌

Token based vs. Cookie based

下面的图解释了这两种方式的工作流 Token based vs. Cookie based

用 token-based 有什么好处?

  • 跨域/CORS

cookies + CORS 在跨域的时候处理的不是很好。而 token-based 方式允许你用 AJAX 调用任何服务,任何域。因为你用的是 HTTP 头来发送你的用户信息。

  • 无状态 (又称 服务端可扩展性)

不需要保存 session,token 保存了用户的信息,并且存放在客户端的 cookies 或者 local storage 上。

  • CDN

你可以把你的资产全扔 CDN 上(比如 javascript,HTML,images,等),你的服务端只需要提供 API。

  • 解耦

你不需要绑定任何认证方式。 token 可以在任何地方产生,因此你的 API 可以从任何地方调用,而仅仅需要授权该调用。

  • 移动优先

当你要实现不同平台(iOS,Android,Windows 8,等等)版本应用的时候,cookies 需要用到该平台的安全 API(你必须处理 cookie 的容器)。而 token-based 就简单多了。

  • CSRF

既然你不需要依赖 cookies 了,你就不需要处理跨站请求了

  • 性能

我们没任何关于性能的硬证据,可是网络回路(比如说从数据库中找一个 session),应该会比计算一个 HMACSHA256 然后验证 token 和解析内容来得慢。

  • 登录页面不再是一个特例

如果你用 Protractor 写测试方法,你不需要再写任何关于登陆的测试了。

  • 标准

你的 API 可以接收标准的 JSON Web Token (JWT)。这是一个标准,并且有很多可用的库(.NET, Ruby, Java, Python, PHP)以及支持他们的公司(比如 Firebase, Google, Microsoft)。比如说, Firebase 允许他们客户用任何的授权机制,只要你生成一个 JWT ,包含了预定义的属性,然后用共享签名来访问他们的API。

什么是 JSON Web Token? JWT(念:揍它)是一个比较新令牌格式,用在有限的存储空间内的。比如说 HTTP 的 Authorization headers。 JWT 是在各部流转的 claims based 间传递加密的一个结构化方法。


实现

假设你已经有 nodejs 应用了,然后你可以找到下面的组件。

服务端

让我们先安装 express-jwtjsonwebtoken :

<!-- lang: js -->
$ npm install express-jwt jsonwebtoken

配置 express 的中间件,用来过滤所有的 /api 请求。

<!-- lang: js -->
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 请求,附带用户认证。

<!-- lang: js -->
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 });
});

GET 一个资源,/api/restricted 直接访问。注意的是,用 expressJwt 中间件 来检查认证非常快。

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

客户端

客户端处理的第一步就是用 AngularJS 来接收 JWT。为了拿到用户信息,我们先创建一个表格,给客户填写用户名和密码。

<!-- lang: js -->
<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>

然后控制器处理提交动作:

<!-- lang: js -->
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。数据持续到把浏览器 tab 关了就失效了。

<!-- lang: js -->
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');
});

然后,我们可以发送一个请求给上面定义的 restricted 资源了:

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

随后你看到服务端输出日志:

<!-- lang: js -->
user foo@bar.com is calling /api/restricted

整套代码在这里,和一个 AngularJS Seed。


下一步?

之后的文章我们将会重温一下:

  • 如何处理社交授权
  • 如何处理session过期

更新:作者三连发

Auth0 源码

转载于:https://my.oschina.net/ilivebox/blog/279440

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值