星路

追寻那一缕星光,在漆黑夜晚前行

0%

【踩坑系列】天猫精灵接入Home Assistant的网关服务没有实现OAuth访问控制

最近在研究天猫精灵接入,根据大神的指引天猫精灵接入HomeAssistant【智能家居技能接入,非webhook调用】,也可以顺利控制yeelight。但发现有一个问题,没有实现OAuth访问控制。即天猫精灵服务器使用获取的token来访问gate.php,OAuth服务器应该进行校验,校验通过后才执行来自天猫精灵服务器的请求。


1.准备


2.过程

2.1.校验功能

1)根据oauth2-server-php官方教程,应该增加如下的Resource Controller代码进行校验。

1
2
3
4
5
6
7
8
// include our OAuth2 Serverobject
require_once __DIR__.'/server.php';
// Handle a request to a resourceand authenticate the access token
if (!$server->verifyResourceRequest(OAuth2\Request::createFromGlobals())) {
    $server->getResponse()->send();
    die;
}
echo json_encode(array('success'=> true, 'message'=> 'You accessed myAPIs!'));

2)但将代码加到gate.php头部,总是验证不通过,经过分析天猫精灵对接api以及研读OAuth2的代码发现了问题。

  • 天猫精灵服务器使用POST方式,以JSON格式(CONTENT_TYPE=’application/json’)传递数据,其中token值在$json->payload->accessToken
  • 而OAuth服务器处理方式是:
    • 接收保存JSON数据,通过标识符’access_token’,即$json->access_token取的token值来判断是否授权  
    • verifyResourceRequest()进行方法校验时,判断是POST请求方式的话,需要满足CONTENT_TYPE=’application/x-www-form-urlencoded’,否则判断失败

3)最终Resource Controller的代码调整如下(当然也可以修改oauth2-server-php相关的处理逻辑代码处理):

1
2
3
4
5
6
7
8
9
10
11
12
require_once __DIR__.'/server.php';
// Handle a request to a resource and authenticate the access token
$request = OAuth2\Request::createFromGlobals();
$response =new OAuth2\Response();
$poststr = file_get_contents("php://input");  //获取天猫精灵服务器请求内容
$obj = json_decode($poststr); //转换成json对象
$request->request=array_merge(array('access_token'=>$obj->payload->accessToken),$request->request);  //根据天猫精灵服务器请求的token值,在OAuth2的request->request对象重新构建一个access_token值
$request->server['CONTENT_TYPE']="application/x-www-form-urlencoded"//重新设置request->server的CONTENT_TYPE值为'application/x-www-form-urlencoded'
if(!$server->verifyResourceRequest($request,$response)) {
$server->getResponse()->send();
die;
}

4)最后,在所有需要访问控制的页面开头的地方都应该加上如上代码即可,比如gate.php。

2.2.token问题

修改server.php

1
2
3
4
5
6
7
8
//server.php
$server = new OAuth2\Server($storage, array(
        'access_lifetime'=>86400  //token有效期,单位s
        ));
//顺便先把允许刷新token的功能开启了
$server->addGrantType(new OAuth2\GrantType\RefreshToken($storage, array(
    'always_issue_new_refresh_token' => true
    )));

使用建议

天猫精灵服务器貌似在token过期后不会自动刷新(虽然api上说是有),过期需要重新在网页登陆授权,所以可以设置有效期长一点,默认的是3600s。