LoginSignup
2
1

KotlinでDynamoDBに接続 - その1

Last updated at Posted at 2023-09-29

概要

AWS Cogniteを使って認証を行いDynamoDBに接続する簡易ログインアプリを作成しました。

プロジェクト全体のソースコードはこちらに置いてあります。
https://github.com/ist-h-i/LoginApp.git

AWSの設定

DynamoDB

DynamoDBの詳細はこちら
https://aws.amazon.com/jp/dynamodb/

テーブルを作成
AWS DynamoDB1.png

SES

メールアドレスを登録
AWS SES.png

Cognite User Pool

User Poolを作成
AWS Cognignt UserPool1.png

SESに登録したメールアドレスを送信元のEメールアドレスに設定
AWS Cognignt UserPool2.png

Cognite ID Pool

ID Poolを作成
AWS Cognignt IDPool1.png
AWS Cognignt IDPool2.png

Cognite IAM

ユーザアクセス > ゲストアクセス > ロールを編集
AWS Cognignt IAM1.png

新しいIAMを作成
AWS Cognignt IAM2.png

許可を追加 > インラインポリシーを作成
AWS Cognignt IAM3.png

アクセス許可にDynamoDBを指定
AWS Cognignt IAM4.png

必要な機能を追加
AWS Cognignt IAM5.png

必要に応じてARNを設定
AWS Cognignt IAM6.png
AWS Cognignt IAM7.png

ロールをアクティブ化
AWS Cognignt IAM8.png

アプリ実装

MainActivity.kt

package com.example.loginapp

import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.amazonaws.auth.CognitoCachingCredentialsProvider
import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBMapper
import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBMappingException
import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBScanExpression
import com.amazonaws.regions.Region
import com.amazonaws.regions.Regions
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient
import com.amazonaws.services.dynamodbv2.model.AttributeValue
import com.example.loginapp.databinding.ActivityMainBinding
import com.example.loginapp.model.User

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 認証情報の取得
        val credentialsProvider = CognitoCachingCredentialsProvider(
            this, "ap-northeast-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
            Regions.AP_NORTHEAST_1 // Region
        )

        // DynamoDBクライアント
        val ddbClient: AmazonDynamoDB = AmazonDynamoDBClient(credentialsProvider)
        // デフォルトではUS-EASTリージョンでクライアント作成されてしまうため明示的にAP_NORTHEASTに設定
        ddbClient.setRegion(Region.getRegion(Regions.AP_NORTHEAST_1))
        val ddbMapper = DynamoDBMapper.builder().dynamoDBClient(ddbClient).build()

        // レイアウト紐付け
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // ログインボタン押下時の設定
        binding.loginButton.setOnClickListener {
            val userId: String = binding.userId.text.toString()
            val password: String = binding.password.text.toString()

            // 未入力欄がある場合
            if (userId.isBlank() || password.isBlank()) {
                showLongToast(R.string.inputUserInfo)
                return@setOnClickListener
            }

            // DynamoDBへのQuery属性
            val eav = HashMap<String, AttributeValue>()
            eav[":v1"] = AttributeValue().withS(userId)
            eav[":v2"] = AttributeValue().withS(password)

            val countExpression =
                DynamoDBScanExpression().withFilterExpression("UserId = :v1 AND Password = :v2")
                    .withExpressionAttributeValues(eav)

            // 外部通信のためスレッド生成
            val queryDynamoDb = Thread {
                try {
                    // Query結果
                    val itemCount: Int = ddbMapper.count(User::class.java, countExpression)
                    if (itemCount != 0) {
                        // User情報が登録済みの場合
                        showLongToast(R.string.loginSuccess)
                        // ログイン後後続処理はこの下に記載
                    } else {
                        // User情報がない場合
                        showLongToast(R.string.loginFailed)
                    }
                } catch (error: DynamoDBMappingException) {
                    showLongToast(R.string.unknownError)
                }
            }
            queryDynamoDb.start()
            try {
                queryDynamoDb.join()
            } catch (error: InterruptedException) {
                Toast.makeText(this, R.string.unknownError, Toast.LENGTH_LONG).show()
            }

        }
    }

    private fun showLongToast(messageInt: Int) {
        // 別スレッドからUIを操作
        val handler = Handler(Looper.getMainLooper())
        handler.post {
            Toast.makeText(this, messageInt, Toast.LENGTH_LONG).show()
        }
    }
}

activity_main.xml

drawableのリソース等は以下参照
https://github.com/ist-h-i/LoginApp.git

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <androidx.cardview.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="30dp"
        app:cardCornerRadius="30dp"
        app:cardElevation="20dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:background="@drawable/custom_edittext"
            android:orientation="vertical"
            android:padding="24dp">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/login"
                android:textAlignment="center"
                android:textColor="@color/lavender"
                android:textSize="@dimen/text_large"
                android:textStyle="bold" />

            <EditText
                android:id="@+id/userId"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:layout_marginTop="40dp"
                android:autofillHints="username"
                android:background="@drawable/custom_edittext"
                android:drawableStart="@drawable/ic_baseline_person_24"
                android:drawablePadding="8dp"
                android:hint="@string/userId"
                android:inputType="textPersonName"
                android:padding="8dp"
                android:textColor="@color/black"
                android:textColorHint="@color/lavender_80" />

            <EditText
                android:id="@+id/password"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:layout_marginTop="20dp"
                android:autofillHints="password"
                android:background="@drawable/custom_edittext"
                android:drawableStart="@drawable/ic_baseline_lock_24"
                android:drawablePadding="8dp"
                android:hint="@string/password"
                android:inputType="textPassword"
                android:padding="8dp"
                android:textColor="@color/black"
                android:textColorHint="@color/lavender_80" />

            <Button
                android:id="@+id/loginButton"
                android:layout_width="match_parent"
                android:layout_height="60dp"
                android:layout_marginTop="30dp"
                android:backgroundTint="@color/lavender"
                android:text="@string/login"
                android:textSize="@dimen/text_middle"
                app:cornerRadius="@dimen/button_corner_radius" />

        </LinearLayout>
    </androidx.cardview.widget.CardView>
</LinearLayout>

まとめ

今回はDynamoDBに接続してみました。
DynamoDBテーブルはスキーマレスであるため、テーブルを作成する際にプライマリキーを除いて属性やデータ型を定義する必要がなく内容の変更が非常に容易です。一方、データの一貫性が担保されないため、エラーハンドリングをアプリ側で徹底するように心がけています。
DBにアクセスできるとやれることの幅が非常に大きくなるので様々なデータベースを使いこなしていきたいです。

2
1
0

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
2
1