Monday, April 16, 2018

JavaScript Plugin Design pattern

Summary
https://stackoverflow.com/questions/10763006/plugin-architecture-in-web-apps-examples-or-code-snippets


Command
http://www.dofactory.com/javascript/command-design-pattern

var calculator = new Calculator();
// issue commands
calculator.execute(new AddCommand(100));
calculator.execute(new SubCommand(24));
calculator.execute(new MulCommand(6));
calculator.execute(new DivCommand(2));


Callback
https://www.w3schools.com/jquery/jquery_callback.asp

slow之后callback函数:
$("button").click(function(){
    $("p").hide("slow", function(){
        alert("The paragraph is now hidden");
    });
});

Dependency Injection
https://github.com/nikku/didi

有点似Factory pattern,根据不同的输入(car)来决定load哪个object。
var Car = function(engine) {
  this.start = function() {
    engine.start();
  };
};

var createPetrolEngine = function(power) {
  return {
    start: function() {
      console.log('Starting engine with ' + power + 'hp');
    }
  };
};


// a module is just a plain JavaScript object
// it is a recipe for the injector, how to instantiate stuff
var module = {
  // if an object asks for 'car', the injector will call new Car(...) to produce it
  'car': ['type', Car],
  // if an object asks for 'engine', the injector will call createPetrolEngine(...) to produce it
  'engine': ['factory', createPetrolEngine],
  // if an object asks for 'power', the injector will give it number 1184
  'power': ['value', 1184] // probably Bugatti Veyron
};


var di = require('di');
var injector = new di.Injector([module]);

injector.invoke(function(car) {
  car.start();
});

Abstract Factory
http://www.dofactory.com/javascript/abstract-factory-design-pattern

var persons = [];
var employeeFactory = new EmployeeFactory();
var vendorFactory = new VendorFactory();

persons.push(employeeFactory.create("Joan DiSilva"));
persons.push(employeeFactory.create("Tim O'Neill"));

Builder
http://www.dofactory.com/javascript/builder-design-pattern

var shop = new Shop();
var carBuilder = new CarBuilder();
var truckBuilder = new TruckBuilder();
var car = shop.construct(carBuilder);
var truck = shop.construct(truckBuilder);

Others
https://seesparkbox.com/foundry/api_patterns_for_your_open_source_javascript_plugin

Ref
Youtube player APIs: https://developers.google.com/youtube/iframe_api_reference
Android lifecycle: https://developer.android.com/guide/components/activities/activity-lifecycle
Android MediaPlayer State Diagram: https://developer.android.com/reference/android/media/MediaPlayer

Alexa
AVS: 怎么用Alexa来做事,如audio player天气预报,交通情况。这是比较generic的,无skill
Smart Home API: 怎么创建一个SH的skill,比较有针对性,AVS不包括的。
Video API: 同上




Wednesday, April 11, 2018

Token简介

Token是什么?
Token是访问某些资源的凭证。打个比喻,我想进入某个公司的办公室,token就是badge,办公室就是我想访问的资源。

为什么需要token?
Token是一个加密字符串,是被访问资源发给客户端的凭证。用户第一次登录给出用户名和密码,之后获得token,以后每次访问均只需要给出token即可,而不需要再登录。资源服务器只要验证token即可。这机制避免了每访问一次都要发密码的需要,从而大大降低密码被截获的可能性。Token实质上是密码的一个替代,但不带任何用户信息。这叫opaque string(不透明),表示一般人不理解,但它对应着用户id。

Refresh token和access token的区别
Refresh token就是上述描述的token,由资源服务器发出,同时资源服务器也会将其保留在DB中。客户登录即获得此token保存在本地存储比如Android的sqlite。当每次需要访问资源就会发出带此token的request,服务器会进行验证。Refresh token不会过期(比如手机上的微信,永远不用重新登录),这会导致一个问题,就是资源服务器没办法revoke或修改这个权限。为了支持动态更改访问权限,引入access token。access token才是真正访问资源的token,它具有较短的有效期(大多数一小时),保证权限大多数情况下最新且更为安全。

Refresh token和access token的关系
htt分用户登录时候,就会即时获得refresh token和access token,每次访问资源用到access token,当access token过期时候,客户端会用refresh token去获得新的access token,同时也会获得新的refresh token。资源服务器也会更新DB中refresh token。access token含有client id的信息,若access token被盗取(compromised)(比如user id和access token不一致,因为黑客试图随意产生access token来骗资源服务器),客户服务器会删除DB中的refresh token,这样access token过期后便不能访问资源,客户端需要重新登录。资源服务器通过access token授权给单一客户端a single authenticated client。例如,用另一个手机登录微信,原手机就会被迫退出并提示安全风险。

资源服务器架构
一般而言,资源服务器含有Auth server和resource server,分别用于验证和提供资源。刚才提到的所有理论都是来自于Auth server。










登录的request
$ curl -X POST -H 'Authorization: Basic dGVzdGNsaWVudDpzZWNyZXQ=' -d 'grant_type=password&username=test&password=test' localhost:3000/oauth/token

{
    "token_type":"bearer",
    "access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiVlx1MDAxNcKbwoNUwoonbFPCu8KhwrYiLCJpYXQiOjE0NDQyNjI1NDMsImV4cCI6MTQ0NDI2MjU2M30.MldruS1PvZaRZIJR4legQaauQ3_DYKxxP2rFnD37Ip4",
    "expires_in":20,
    "refresh_token":"fdb8fdbecf1d03ce5e6125c067733c0d51de209c"
}


更新access token的request
curl -X POST -H 'Authorization: Basic dGVzdGNsaWVudDpzZWNyZXQ=' -d 'refresh_token=fdb8fdbecf1d03ce5e6125c067733c0d51de209c&grant_type=refresh_token' localhost:3000/oauth/token

{
    "token_type":"bearer",
    "access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiVlx1MDAxNcKbwoNUwoonbFPCu8KhwrYiLCJpYXQiOjE0NDQyNjI4NjYsImV4cCI6MTQ0NDI2Mjg4Nn0.Dww7TC-d0teDAgsmKHw7bhF2THNichsE6rVJq9xu_2s",
    "expires_in":20,
    "refresh_token":"7fd15938c823cf58e78019bea2af142f9449696a"
}


Token是访问资源的凭证。比如Hulu想发events给A公司,Amazon公司就需要给Hulu一个token。这里的token叫LWA token (Login with Amazon)。又如,vtasters提供FB login,FB就给vtasters一个access token取访问FB的资源,当然第一次用FB login时候,会出现一个页面告知用户哪些FB信息(例如生日)会被vtasters访问。这叫scope,是能访问资源的范围,这种给予第三方的token权限一般比第一方的权限低。

OAuth token
refresh token(never expire) refresh tokens have a very long duration (month to unlimited) and are stored at the client in a persistent storage (e.g. database or filesystem)
bearer token=access token(an hour): user's permission scope
correlation token: A token that identifies the message exchange. map to 用户id
LWA token: amazon第三方token
MAP token: amazon第一坊token
auth token key

怎么防止篡改token
要求token的时候,加入一个client secret加密的字符串即可,验证此request是否来自于官方的app。这个client secret只有client app和server知道。所以通过这个方法就可以验证token request是否被篡改,如client assertion和用户名密码一起发送获取access token。client assertion又叫JWT(json web token)就是用client key对一些字段进行加密发到server端,它有一套工业标准。

headers = json.dumps({
    "typ" : "JWT",
    "alg" : "HS256"
})
claims = json.dumps({
    "iss": "mozillazg.com",
    "exp": 1435055117,
    "user_id": 1,
    "foo": "bar"
})
content = base64url_encode(headers) + '.' + base64url_encode(claims)
secret_key = 'your secret key'
signature = hmac.new(secret_key, content, hashlib.sha256).digest()

token = content + '.' + base64url_encode(signature)

curl -X POST -H 'Authorization: B

Token的历史
API keys
Google maps用的就是API key,只要从Google获取,每次request加入key即可访问。
用户场景:公司内部应用,不需访问与用户相关的数据。

OAuth Token
第三方Facebook Login. 用户需同意第三方可访问FB的scope获refresh/access token。对比与API keys,好处是限定访问资源范围,会过期减少资源不法访问的可能,access token可以revoke(删除其在数据库的记录)。

Json web token
OAuth token的进化版,客户端对字符串进行加密,server端进行验证。可避免数据库查找access token。
用户场景:减少数据库访问,且不需要立即revoke token。

Page token:
Page token与start index。page token是该search搜索结果的该页的最后一个item的hash,这样获取下一页的时候就可以知道从哪开始。好处是即使有新收据加入,获取下一页的时候也有可能得到。坏处是只能按顺序获取,也就是不能从一页跳到第10页,所以用于Infinite scrolling.

Ref:
https://stackoverflow.com/questions/25838183/what-is-the-oauth-2-0-bearer-token-exactly
https://auth0.com/learn/refresh-tokens/
https://jwt.io/
https://mozillazg.com/2015/06/hello-jwt.html
https://zapier.com/engineering/apikey-oauth-jwt/
Page token作用