LoginSignup
3
1

More than 5 years have passed since last update.

コンビニで買った育てるサラダをrasPiで撮ってKinesisに流してゴニョゴニョする 後の中編

Last updated at Posted at 2018-11-21

さて、続きであります。

もういい加減タイトル変えたほうがわかりやすい気もしてますが、ゴニョゴニョの部分はおおよそ、

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がよしなにしてくれるし。

app.py
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-streamchalice deploy してます。

でlambdaと同時にapi-gatewayも作ってくれたのでそこの設定から。

・・お、ちょっと待って。
chaliceにauthrizerってのがあるの?

こんな感じにして試してみよう

app.py
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...

19.png

な、

な、

なんと!

ちなみにこの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を少し書き換えてみる

src/components/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にセットしてやるというなんか微妙な方法となりました。

まあ、いけたはいけた

20.png

このendpointのURLがlambda関数が返したやつ

ちなみに主だったとこは今のとここんな感じです。
ちなみにkinesis video streamのget_data_endpointでARNとName両方指定してたらどっちかにしろって怒られた。

app.py
@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 
HelloWorld.vue
  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じゃアカンな。。
さて、あとは再生だけだー。いよいよ次回で終わりの予定。

しかし、作業しながら流れで書いてるので基本、間違ってもそのまま突き進み、足跡も残していくスタンスです。あとで振り返ってまとめるとか苦手。というかあんまり見る人にやさしくしてない。

3
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1