概要
AWS Cogniteを使って認証を行いDynamoDBに接続する簡易ログインアプリを作成しました。
プロジェクト全体のソースコードはこちらに置いてあります。
https://github.com/ist-h-i/LoginApp.git
AWSの設定
DynamoDB
DynamoDBの詳細はこちら
https://aws.amazon.com/jp/dynamodb/
SES
Cognite User Pool
SESに登録したメールアドレスを送信元のEメールアドレスに設定
Cognite ID Pool
Cognite IAM
アプリ実装
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にアクセスできるとやれることの幅が非常に大きくなるので様々なデータベースを使いこなしていきたいです。