本節來討論Alexa Skill中涉及到的授權問題。
Alexa內功能的授權
Alexa會發給skill用戶的token,然后skill代碼使用這個token來訪問Web API訪問用戶的Alexa內的功能,如list等。
授予skill第三方的權限——Account Linking
參考:https://developer.amazon.com/docs/account-linking/understand-account-linking.html#account-linking-and-the-skill-model
授予skill用戶在其他第三方系統中的權限,例如,讓亞馬遜echo控制你的智能門鎖,就需要授予特定的skill能訪問你門鎖的權限。但是門鎖權限本來是門鎖制造商的雲管理的,也就是說你要使用門鎖的App控制,那么如何實現將這個權限授予skill呢?這就需要使用Oauth2.0來實現。
OAuth中定義了一些角色,但是只看OAuth的說明會比較抽象,所以亞馬遜非常好的給出了OAuth角色在Alexa Skill中具體指什么。這里簡單翻譯一下Smart Home Skill的對應關系方便理解。在Smart Home Skill中,要求使用Authorization code grant模式。該模式中,authorization server在用戶登錄時返回一個code,然后Alexa使用這個code去access token endpoint請求一個access token/refresh token pair;這個refresh token可以被用來在token過期時請求信的token。
- Resource owner:指使用這個skill綁定自己設備的Alexa用戶。該用戶在設備廠商的雲中有對應的賬號來控制此設備。
- Resource server:一般指設備廠商的雲服務器。受保護的資源就是用戶智能家居的信息和控制權。拿智能門鎖來講就是門鎖廠商的服務器。
- Client:指Skill。因為Skill使用獲得的憑證去resource server訪問授權的資源,但是是Alexa請求authorization server獲得access token。
- Authorization server:用來認證用戶並提供access token憑證的服務器。舉例來講,一般就是智能門鎖廠商的服務器。當然,資源服務器和授權服務器不必須是同一個個人或者公司所有。門鎖的公司可能支持你使用亞馬遜或者微信的賬號來登陸,那么授權服務器就變成了亞馬遜或者微信的服務器。
在擁有了一些背景知識后,下面來了解一下具體的工作流程,從用戶的角度,看到的是這樣的流程:
- Alexa app中用戶點擊Enable來開始賬戶關聯過程。
- app顯示讓用戶登錄第三方系統(門鎖公司)的界面。
- 用戶輸入用戶名密碼登錄成。
- 用戶被重定向回Alexa app的界面。
當用戶關聯成功后,Alexa就獲得並存儲代表了用戶的access token。Alexa給skill的每個請求中,都會攜帶這個token方便你skill來使用訪問第三方系統。由此產生幾個疑問:Alexa是如何獲得到token,並關聯到這個Alexa賬戶的?Alexa會調用安卓的瀏覽器,瀏覽器和Alexa是怎么通信的?其實亞馬遜官方文檔很好的解答的這些疑問,如下圖所示。
-
Alexa app彈出的登陸界面就是讓用戶跟Authorization server認證,這個訪問的URI也就是skill中設置的
Authorization URI
。當Alexa app調用這個URI時還上報了一些參數,如state, client_id, response_type, scope, redirect_uri 。這些參數也是skill開發者可以設置的。如client_id可以向認證服務器說明是哪個skill(好像這個client_id很容易被竊取?因為是從客戶端發出去的。但是,還需要設置一個client_secret,這個secret是存在Alexa雲的,Alexa在獲得到code
后(誰都可以聲稱自己是Alexa的這個skill來獲得code
),Alexa使用code+client_secret+clietn_id三者來獲得token,由於攻擊者無法獲得secret,所以攻擊者無法獲得access_token,OAuth還是設計的挺安全的,亞馬遜似乎也沒用錯。當然,這需要第三方廠商,如門鎖的廠商去檢查並記錄發出的code
和client_id
和client_secret
的對應關系。參考);scope似乎是權限的具體說明,這個就要跟第三方的服務器配合來設置了;state是一個隨機的會話標記,需要在重定向用戶到亞馬遜URI的時候傳回去,讓亞馬遜服務器知道是這個會話。 -
用戶認證過后,authorization server 生成authorization code(
code
),頁面重定向用戶到Alexa特定的redirect_uri
,這是亞馬遜的URI,並且在重定向時發送code
和state
參數。 -
接下來Alexa就可以用
code
來請求access token了,請求的URI是skill里設置的authorization server的Access Token URI
。 -
Alexa保存好access token和refresh token。至此,Alexa賬戶就和第三方的賬號(使用token)關聯了。
-
當用戶給skill發請求時,如IntentRequest,就會把這個
access_token
發給skill,skill的代碼就可以隨意使用用戶的token憑證了。
授予第三方雲Alexa的權限
用戶在Alexa中添加了設備后,肯定希望設備的狀態可以自動的異步發送到Alexa App中,用戶隨時查看都是最新的狀態。而這個Alexa App又是亞馬遜所有的,於是需要授予第三方更新Alexa app中這個設備的權限,基本原理也是將亞馬遜賬號的權限用OAuth協議分享給第三方雲。
- 當用戶enable啟用skill並完成賬戶關聯后,Alexa會向skill發送
AcceptGrant
指令,攜帶該Alexa用戶的code
和上一步從第三方雲拿來的access_token,這個code就代表了Alexa用戶的權限; - 第三方雲此時需要用
code
換Alexa的access_token(Oauth的流程,除了code還要發送代表該skill的client_id和client_secret,亞馬遜認證是哪個skill發出的推送),同時進行該用戶Alexa賬號和第三方雲賬號的關聯。 - 當關聯好后,每當第三方廠商雲檢測到該用戶的設備狀態發生變化,比如鎖被用指紋打開了,就使用該用戶對應的Alexa上的token向亞馬遜預設好的event事件結點URL發送POST請求,該請求中需要攜帶設備狀態、Alexa雲中該設備的ID(
endpointId
,這樣亞馬遜才知道要更新哪個設備狀態,設備的ID在discover的時候上報),攜帶Alexa的access_token(疑問:這個access_token的權限范圍是多少?亞馬遜對權限的管控能區分出用戶的哪個設備對應哪個Alexa access_token嗎?答:有能力做到,因為Alexa雲清楚的知道access_token給的哪個skill,如步驟2所述;同時設備ID又是skill來上報的。但是需要實驗證明Alexa有沒有做這個檢查。)