さて、続きであります。
もういい加減タイトル変えたほうがわかりやすい気もしてますが、ゴニョゴニョの部分はおおよそ、
cognitoで無駄にアカウント管理と認証をしつつ、コンテンツはS3に置きつつ、api gatewayを通したlambdaでkinesis video streamのエンドポイントを引っ張ってきて、それをvuejsなりで再生させる
です。
前回はcogniteの部分だけなんとなくやったので今日はlambdaの所でしょうか。
おおよそは・・
AWS Cognito の認証情報を API Gateway + Lambda で受け取りたい
Cognito ユーザープールを単独で API GateWay と共に使う
上記を参考にさせていただこうかと思います。
言語は迷うな。サンプルを生かすならnodejsがいいのかな。
でもboto3使えば簡単にできそうな気もするな。pythonにしよう。
それから、実はvuejsは初めてつかってんだけど、vuejsの場合の$.ajaxみたいなのはこれかな。
なんとなくイメージできました。
lambdaとgatewayから
まずは参考サイトのように適当なHelloWorld作っておきます。
あ、でもせっかくだからskeltonみたいなのにしとこう。path決めとけばchaliceがよしなにしてくれるし。
from chalice import Chalice
import logging
import os
import json
import boto3
from botocore.vendored import requests
logging.basicConfig()
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
app = Chalice(app_name='auth-raspi-stream')
cognito = boto3.client('cognito-idp')
kvs = boto3.client('kinesisvideo')
streamname = os.environ.get('KVS_STREAM_NAME')
streamarn = os.environ.get('KVS_STREAM_ARN')
@app.route('/')
def index():
return {'hello': 'world'}
@app.route('/get_kvs_endpoint', methods=['GET'], content_types=['application/json'])
def get_kvs_endpoint():
event = app.current_request.json_body
logger.debug(json.dumps(event))
token = event['accessToken']
try:
response = cognite.get_user(
AccessToken='string'
)
if 'Username' in response:
raise Exception
endpoint = get_data_endpoint(
StreamName=streamname,
StreamARN=streamarn,
APIName='GET_HLS_STREAMING_SESSION_URL'
)
if 'DataEndpoint' in endpoint:
return {status: -1, 'endpoint': endpoint['DataEndpoint']}
else:
raise Exception
except:
return {status: -1, 'endpoint': False}
だいたいこんなのを作っておきました。その前後に chalice new-project auth-raspi-stream
と chalice deploy
してます。
でlambdaと同時にapi-gatewayも作ってくれたのでそこの設定から。
・・お、ちょっと待って。
chaliceにauthrizerってのがあるの?
こんな感じにして試してみよう
from chalice import Chalice,CognitoUserPoolAuthorizer
import logging
import os
import json
import boto3
from botocore.vendored import requests
logging.basicConfig()
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
app = Chalice(app_name='auth-raspi-stream')
cognito = boto3.client('cognito-idp')
kvs = boto3.client('kinesisvideo')
streamname = os.environ.get('KVS_STREAM_NAME')
streamarn = os.environ.get('KVS_STREAM_ARN')
cognitopoolarn = os.environ.get('COGNITO_POOL_ARN')
cognitopoolname = os.environ.get('COGNITO_POOL_NAME')
streamarn = os.environ.get('KVS_STREAM_ARN')
authorizer = CognitoUserPoolAuthorizer(
cognitopoolname, provider_arns=[cognitopoolarn])
@app.route('/', methods=['GET'], authorizer=authorizer)
def index():
return {'hello': 'world'}
~~(略
(これとは別にconfig.jsonも追記とかしてます)
そしてdeploy...
な、
な、
なんと!
ちなみにこのURLを直叩きすると {"message":"Unauthorized"}
ってかえってくるのでフィルターは機能はしているもよう。
これは素敵すぎる。/get_kvs_endpointの方にもauthrizer付けちゃおう。
でもその前にfrontからapi叩くところをやっておく。
api 叩いてみる
npm install --save-dev axios
import axios from 'axios';
をsrc/main.jsに追記
で、このsampleのHome.vueを少し書き換えてみる
<script>
import axios from 'axios';
export default {
name: 'Home',
data () {
return {
info: null
}
},
mounted: () => {
axios
.get('https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/api/')
.then(response => (this.info = response))
}
}
</script>
を足してみた。
それでページ見てみたら、
Access to XMLHttpRequest at 'https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/api/' from origin 'xxxxxxxx' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
createError.js?16d0:16 Uncaught (in promise) Error: Network Error
at createError (createError.js?16d0:16)
at XMLHttpRequest.handleError (xhr.js?ec6c:87)
みたいなエラーは出てたけどまあなんか動いてそうなきがする。
でもなんかこれちょっとめんどいやつかもな。awsじゃないサーバー(gcp)上で動かしてみてたからやろか。と思ったけど、そんなめんどくもないかもしれん。
Amazon API Gateway をクロスオリジンで呼び出す (CORS)
いや、こっちか。
って、apigatewayもlambdaもallow-origin返すようにしたのにまだアカン。
そもそも認証の問題かな。
レスポンスヘッダにx-amzn-errortype: UnauthorizedException
とかあるし。実は401はかえってきてるんよね。もうちょっとchaliseのauthorizerのところ読み込まんとあかんか。
あ、普通にvuejsの方でAuthorizationヘッダ設定してないだけか。
amplifyのこれでaccessTokenとかとれるみたいなので、、
import { Auth } from 'aws-amplify';
Auth.currentSession()
.then(data => console.log(data))
.catch(err => console.log(err));
んー。sessionとってAuthorizationヘッダに入れるようにしてみてるけど403が返ってきてうまくいかないなー。
・・でですねー、結局ここからかなり詰まる。
まずAmplifyにAPIクラスがあるのを発見し、これを使おうとする。
認証後にこれのAPI.getをたたくとOPTIONヘッダのとこはクリアしたのでCORSは大丈夫っぽかったんだけど、そのあとのGETリクエストでUnauthorizeが返ってくる。。
見本通りにやってるんだけどなー。
ただ、Authorizationヘッダの中身が
AWS4-HMAC-SHA256 Credential=XXXXXXXXXXXXXXX/us-west-2/execute-api/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-security-token, Signature=XXXXXXXXXXXXXXXXXXXX
みたいになってて、なんか思ってたトークンと違うなぁと。
結局、こんな感じでsessionからjwtTokenを引っこ抜き、マニュアルでheaderにセットしてやるというなんか微妙な方法となりました。
まあ、いけたはいけた
このendpointのURLがlambda関数が返したやつ
ちなみに主だったとこは今のとここんな感じです。
ちなみにkinesis video streamのget_data_endpointでARNとName両方指定してたらどっちかにしろって怒られた。
@app.route('/', methods=['GET'], content_types=['application/json'], authorizer=authorizer, cors=True)
def get_kvs_endpoint():
endpoint = False
try:
endpoint = kvs.get_data_endpoint(
StreamARN=streamarn,
APIName='GET_HLS_STREAMING_SESSION_URL'
)
logger.debug(str(endpoint))
if 'DataEndpoint' in endpoint:
res = {"statusCode" : 200,
"body" : endpoint["DataEndpoint"],
"headers" : {"Content-Type" : "application/json", "Access-Control-Allow-Origin": "'*'"}}
return res
else:
raise
methods:{
signIn: function () {
Auth.signIn(this.userInfo.username, this.userInfo.password)
.then((data) => {
this.message_text = 'ログインしました';
this.status = 'こんにちは、'+data.username+'さん';
}).catch((err) => {
this.message_text = 'ログインできませんでした';
});
},
play: async function() {
const self = this
const session = await Auth.currentSession()
//const token = await Auth.currentSession().idToken.jwtToken
console.log(await session.idToken)
Auth.currentSession()
.then(session => session.idToken.jwtToken)
.then(token => API.get('RaspiStream', '/',{"headers":{"Authorization":token}}))
.then(response => (self.info = response.body))
.catch(err => console.log(err));
},
}
いつまでもHelloWorld.vueじゃアカンな。。
さて、あとは再生だけだー。いよいよ次回で終わりの予定。
しかし、作業しながら流れで書いてるので基本、間違ってもそのまま突き進み、足跡も残していくスタンスです。あとで振り返ってまとめるとか苦手。というかあんまり見る人にやさしくしてない。