Blogical

AWS/Salesforceを中心に様々な情報を配信していきます(/・ω・)/

【iOS】Amazon Cognito/AWS Amplifyを用いたログイン機能の実装

こんにちは、ロジカル・アーツの福島です。

今回はiOSアプリの中でよく見られるユーザーログイン機能の実装を、AWSのサービスであるAmazon CognitoとAWS Amplifyを用いて行いたいと思います。

はじめに

今回はAmplify公式ドキュメントを参考に解説していきます。以下の前提条件の下で手順を進めていきますが、バージョンにより実装が異なる可能性がありますので、詳しくは公式ドキュメントを参照してください。

前提条件

今回の実装は以下のような環境で行います。

項目 バージョン
OS macOS BigSur 11.4
Xcode 12.5.1
Swift 5.4.2
Node.js 14.17.0
npm 7.17.0
git 2.32.0
AWS CLI 2.2.8
CocoaPods 1.10.1
Amplify 5.1.0

手順

環境構築

まずは前提条件にあるツール群のインストールから行います。

Xcode・Swift

XcodeApp Storeからインストールすることが可能です。(インストールはこちら

インストール後、ツールバーから「Xcode→About Xcode」を選択して、version 11.4以降であることを確認してください。

また、Swiftは標準でインストールされているかと思いますので、バージョンを確認したい場合は以下のコマンドをターミナルで実行してください。

$ swift --version

Apple Swift version 5.4.2 (swiftlang-1205.0.28.2 clang-1205.0.19.57)
Target: arm64-apple-darwin20.6.0

Node.js・npm

Amplifyはnpmまたはcurlを用いてインストールすることができます。npmでインストールしたい方はまずNode.jsおよびnpmをインストールする必要があります。

これらは公式HPからインストーラをダウンロードすることで簡単にインストールできます。

インストール後に以下のコマンドを実行して、正常にインストールできているかを確認して下さい。

$ node -v
v14.17.0
$ npm -v
7.17.0

git

macではgitが標準でインストールされているので、以下のコマンドを実行してバージョンがv2.14.1以上かを確認してください。

$ git --version
git version 2.32.0

AWS CLI

ターミナル上でawsリソースの操作などが可能になるAWS CLIバージョン2をインストールします。

公式HPから、インストーラをダウンロードします。

インストーラの手順に従ってインストールが完了したら、以下のコマンドを実行して正常にインストールできているかを確認してください。

$ which aws
/usr/local/bin/aws

CocoaPods

Swiftのライブラリ管理を行うCocoaPodsをインストールします。

Macにはデフォルトでgemコマンドがインストールされているので、以下のコマンドを実行します。

$ sudo gem install cocoapods

インストールに成功したら、CocoaPodsをセットアップするために以下のコマンドを実行します。

$ pod setup

Setup completedと表示されたらCocoaPodsのセットアップは完了です。

Amplify CLI

Amplify CLInpmcurlのどちらかでインストールします。

npmを用いたインストール

$ npm install -g @aws-amplify/cli

curlを用いたインストール

$ curl -sL https://aws-amplify.github.io/amplify-cli/install | bash && $SHELL

次に、Amplify CLIの設定を行います。

$ amplify configure

上記を実行するとブラウザが立ち上がり、マネジメントコンソールのサインインを求められ、新しいIAMユーザーを作成できます。既にIAMユーザーがある場合や、AWS CLIの設定を既に行っている場合はそちらの設定を引き継げるので、この手順は不要です。

※既にお持ちのIAMユーザーを使用される場合は、正しいIAMポリシーが適用されているかを確認してください。

セットアップ

アプリケーションでAmplifyを使用できるようにするためのセットアップを行います。

アプリケーションの作成

今回ログイン機能を実装するアプリケーションを作成します。

まずXcodeを開き、Create a new Xcode projectを選択します。 iOSのAppを選択し、以下のような設定で作成します。

f:id:logicalarts:20210709103547j:plain

公式ドキュメントではSwiftUIで作成をしていますが、本記事ではStoryboardで作成します。

Amplifyライブラリのインストール

今回はCocoaPodsを用いてライブラリをインストールします。

アプリケーションがあるディレクトリに移動して、pod initを実行します。

$ cd ~/path/to/MyAmplifyApp
$ pod init

現在のディレクトリにPodfileが作成されますので、Podfilevimテキストエディタで開き、使用するライブラリを入力します。

target 'MyAmplifyApp' do
  use_frameworks!

  pod 'Amplify'
  pod 'AmplifyPlugins/AWSCognitoAuthPlugin'

end

Podfileを保存したら、以下のコマンドを実行してください。

$ pod install --repo-upadte
# M1チップ搭載のmacをお使いの場合、上記のコマンドではpodを使用できない場合があります。その場合以下のコマンドを使用してください。
# arch -x86_64 pod install --repo-update

インストールに成功したら現在のディレクトリにMyAmplifyApp.xcworkspaceが作成されますので、そちらのプロジェクトを開いてください。

バックエンド設定

続いて、Amplify CLIを用いてプロジェクトでAWSリソースを使用できるようにします。

アプリケーションがあるディレクトリまで移動しamplify initを行い、設定を行っていきます。

$ cd ~/path/to/App/MyAmplifyApp
$ amplify init

? Enter a name for the project
    MyAmplifyApp
? Enter a name for the environment
    dev
? Choose your default editor:
    Visual Studio Code
? Choose the type of app that you're building
    ios
? Do you want to use an AWS profile?
    Yes
? Please choose the profile you want to use
    default

amplify initに成功したら、現在のディレクトリに2つのJSONファイル(amplifyconfiguration.jsonawsconfiguration.json)が作成されます。

この2つのJSONファイルをXcodeのプロジェクト直下にドラッグ&ドロップで追加してください。

f:id:logicalarts:20210709104009j:plain

f:id:logicalarts:20210709104125p:plain

  • Copy items if needed
  • Create groups
  • MyAmplifyApp

にチェックが入っていることを確認し、確定してください。

次に、Authカテゴリを追加するため、以下の2つのコマンドを実行します。

$ amplify add auth

? Do you want to use the default authentication and security configuration?
    `Default configuration`
? How do you want users to be able to sign in?
    `Username`
? Do you want to configure advanced settings?
    `No, I am done.`
$ amplify push

これで新しいCognitoユーザープールが作成され、紐づけられました。ユーザープールの詳細については、マネジメントコンソール上で確認することができます。

また、既に作成しているユーザープールを紐付けたい場合、以下のコマンドを実行してください。

$ amplify import auth

アプリケーション設定

次に、アプリケーション側でAmplifyを使うための設定を行います。

AppDelegate.swiftを開き、Amplifyをインポートし、didFinishLaunchingWithOptionsに以下のコードを入力してください。

// AppDelegate.swift

import Amplify
import AmplifyPlugins

・・・中略・・・

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    do {
        try Amplify.add(plugin: AWSCognitoAuthPlugin())
        try Amplify.configure()
        print("Amplify configured with auth plugin")
    } catch {
        print("Failed to initialize Amplify with \(error)")
    }
    return true
}

これでセットアップは完了です。

ユーザーの登録

アプリでサインアップを実装することもできますが、今回はCLIでユーザーの登録を行ってみたいと思います。

まず、今回作成したCognitoユーザープールIDを調べます。

$ aws cognito-idp list-user-pools --max-results 20

{
    "UserPools": [
        {
            "Id": "ap-northeast-1_XXXXXXXXXX",
            "Name": "myamplifyappXXXXX_userpool_XXXXXX-dev",
            "LambdaConfig": {},
            "LastModifiedDate": "XXXXXXXXXX",
            "CreationDate": "XXXXXXXXXX"
        }
    ]
}

表示されたユーザープールIDを使用して、以下のコマンドを実行します。

$ aws cognito-idp admin-create-user \
--user-pool-id ap-northeast-1_XXXXXXXXXX \
--username tarotanaka \
--user-attributes Name=email,Value="foobar@example.com" Name=email_verified,Value=true

これでtarotanakaというユーザーが作成されました。

ただし、この作成方法の場合、ユーザーのステータスがFORCE_CHANGE_PASSWORDとなっており、ログインできません。

以下のコマンドでパスワードを再設定します。

$ aws cognito-idp admin-set-user-password \
--user-pool-id ap-northeast-1_XXXXXXXXXX \
--username tarotanaka \
--password 'L0gicaL4rts' \
--permanent

これでユーザーのステータスがCONFIRMEDとなり、ログインできるようになりました。

ログイン

ユーザー名とパスワードでログインするViewを作成します。

f:id:logicalarts:20210712100315p:plain

// ViewController.swift 

import Amplify

class ViewController: UIViewController {

    // 各々のオブジェクトとコードを紐付け
    @IBOutlet weak var usernameTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!
    @IBOutlet weak var messageLabel: UILabel!

    // 画面がロードされた際の初期化
    override func viewDidLoad() {
        super.viewDidLoad()
        messageLabel.text = "ログインしてください"
    }

    // LOGINボタン押下時の挙動
    @IBAction func logIn(_ sender: Any) {
        let username = usernameTextField.text!
        let password = passwordTextField.text!
        signIn(username: username, password: password)
    }

    // ユーザーログイン機能
    func signIn(username: String, password: String) {
        Amplify.Auth.signIn(username: username, password: password) { result in
            switch result {
            case .success:
                self.changeMessage(message: "ログイン成功!")
                print("Sign in succeeded")
            case .failure(let error):
                self.changeMessage(message: "ログイン失敗…")
                print("Sign in failed \(error)")
            }
        }
    }

    // messageLabelのテキストを変更
    func changeMessage(message: String) {
        DispatchQueue.main.async {
            self.messageLabel.text = message
        }
    }
}

AmplifyライブラリのAuth.signInメソッドを使用することで簡単にログインすることが可能です。

f:id:logicalarts:20210709140533p:plain

ログアウト

ログアウトボタンを追加します。以下のコードをViewController.swiftのViewControllerクラスに追記してください。

// LOGOUTボタン押下時の挙動
@IBAction func logOut(_ sender: Any) {
    signOut()
}

// ログアウト機能
func signOut() {
    Amplify.Auth.signOut(options: .init(globalSignOut: true)) { result in
        switch result {
        case .success:
            self.changeMessage(message: "ログアウトしました")
            resetTextField()
            print("Successfully signed out")
        case .failure(let error):
            self.changeMessage(message: "ログアウトに失敗しました")
            print("Sign out failed with error \(error)")
        }
    }
}

// テキストフィールドの初期化
func resetTextField() {
    DispatchQueue.main.async {
        self.usernameTextField.text = ""
        self.passwordTextField.text = ""
    }
}

起動時にログイン状態を確認する

現在アプリでは、起動時にmessageLabelを「ログインしてください」という文字列に初期化するように記述しています。

・・・
override func viewDidLoad() {
    super.viewDidLoad()

    messageLabel.text = "ログインしてください"
}
・・・

これではログインしたままアプリを再起動させた場合、ログインしているにも関わらず「ログインしてください」と表示されてしまいます。

これを改善するために、起動時にログイン状態を確認するようにしてみましょう。

・・・
override func viewDidLoad() {
    super.viewDidLoad()

    // 現在同端末でログインしているユーザーがいるかの確認
    if Amplify.Auth.getCurrentUser() != nil {
        messageLabel.text = "ログインしています"
    } else {
        messageLabel.text = "ログインしてください"
    }
}
・・・

これで起動時にログイン状態を確認し、messageLabelに表示することができます。

f:id:logicalarts:20210709142109p:plain

起動時にログインしている場合、messageLabelは「ログインしています」となります。

これでログインとログアウトの機能を実装することが出来ました。

まとめ

今回はAmazon CognitoとAWS Amplifyを用いてiOSアプリのログイン機能を実装しました。

環境構築としてCLIツールのダウンロードはありますが、実装自体は非常に簡単に出来ることが分かります。

また、今回はCLIを使用してデフォルト設定のCognitoユーザープールを作成しましたが、マネジメントツールからカスタマイズしたユーザープールを作成してそれをアタッチすることもできます。

ログイン機能以外にも、非常に便利なライブラリやメソッドが揃っているので是非使用してみてください。

参考文献