LoginSignup
1
0

[SwiftUI / Auth0]Auth0 を利用した iOS アプリの開発

Last updated at Posted at 2023-08-03

この記事を書いた動機

Auth0 を利用した iOS アプリ(SwiftUI)の開発に関する記事はあるが、画面の表示を担当する ContentView に認証に関する処理を実装するものが多かった。

メンテナンスしやすいように認証に関する処理を別のクラスに実装したので、その備忘録として書いた。

この記事で書くこと・書かないこと

書くこと

  • Auth0 を利用した iOS アプリ(SwiftUI)開発

書かないこと

  • Auth0 のアカウント作成方法
  • Auth0 で新しい Application(Native App) の作成方法
  • Auth0 でテストで使用するユーザーの具体的な作成方法
  • Xcode を利用して新しいプロジェクト(SwiftUI)を作成する方法
  • Xcode の Add Package を利用してライブラリを導入する方法
  • プロジェクトに .plist ファイルを追加する方法

上記の内容は記載しないため、具体的な方法については他の記事を確認すること

Auth0 とは

  • クラウド型の認証プラットフォーム
  • ユーザのログイン情報やトークンの管理などを自社開発のアプリに導入できる

画面イメージ

ログイン画面

ユーザーが Log in ボタン を押すと、アプリは認証画面を表示する

認証画面

ユーザーがこの画面で、メールアドレス・パスワードを入力し Continue ボタン を押すと、アプリは Auth0 を利用して認証処理を実行する

  • 認証処理が成功したら、ログイン状態になりホーム画面に遷移する

ホーム画面

アプリは、ユーザー名とユーザーの画像を表示する

  • ユーザーが Log out ボタン を押すと、Auth0 を利用してログオフ状態になりログイン画面に遷移する

前提条件

  • 事前に Auth0 のアカウントを作成していること
  • Xcode を利用してプロジェクト(SwiftUI)を作成していること

開発環境

項目 内容 備考
PC MacBook Air M1 2020
IDE Xcode ver 14.3.1
バージョン管理 GitHub

GitHub

実際のコードを下記リポジトリにプッシュしている

上記 GitHub のコードには Auth0 ファイル(.plist 形式) をプッシュしていないため、各自 Auth0 のファイルを作成、設定すること

追加するライブラリ

  • Auth0
  • JWTDecode
  • SimpleKeyChain

Xcode の Add PackageAuth0 を指定しインポートを実行すると、自動的に JWTDecode SimpleKeyChain も自動的に反映される。

ディレクトリ・ファイル構成

次の通り
スクリーンショット 2023-08-03 21.45.21.png

Auth0 で準備すること

Application(Native App) を作成する

image.png

作成した Application の項目に値を設定

設定対象の項目は次の通り

  • Allowed Callback URLs
  • Allowed Logout URLs

設定する値は次の通り

{BundleID}://{Auth0 Domain}/ios/{BundleID}/callback

項目
BundleID sample.Sample-App-with-Auth0
Auth0 Domain dev-XXXXXXXXXX.us.auth0.com

設定する値

sample.Sample-App-with-Auth0://dev-XXXXXXXXXX.us.auth0.com/ios/sample.Sample-App-with-Auth0/callback

テストで使用するユーザーを作成する

この作成したユーザーのメールアドレスとパスワードを利用して、ログインが可能。
image.png

クラス一覧

名称 役割 備考
Sample_App_with_Auth0App エントリーポイント
Auth0Service Auth0を利用した認証情報を各クラスに提供 ObservableObject を準拠する
ContentView 認証の状況に応じて表示する画面を切り替える
HomeView ログイン後の画面
LoginView ログイン前の画面

このクラス構成にした理由

  • Auth0 を利用した認証に関する処理は Auth0Service クラス に、画面に関する処理は 各 View クラス に分けて記載したかったため

コード

Auth0Service クラス

Auth0Service.swift
import Foundation
import Auth0

class Auth0Service:ObservableObject {
    @Published var isAuthenticated = false
    @Published var userProfile = Profile.empty

    internal func login() {
        Auth0
            .webAuth()
            .start { result in
                switch result {
                case .success(let credentials):
                    print("Obtained credentials: \(credentials)")
                    self.isAuthenticated = true
                    self.userProfile = Profile.from(credentials.idToken)
                case .failure(let error):
                    print("Failure: \(error.localizedDescription)")
                }
            }
    }
    
    internal func logout(){
        Auth0
            .webAuth()
            .clearSession { result in
                switch result {
                case .success:
                    print("Session cookie cleared")
                    self.isAuthenticated = false
                    self.userProfile = Profile.empty
                case .failure(let error):
                    print("Failed with: \(error.localizedDescription)")
                }
            }
    }
}

ポイント

  • ログイン状態を isAuthenticated に保持している
  • ObservableObject を準拠しているため isAuthenticated の値が変化すると、他のクラスにもそれが伝播する

Sample_App_with_Auth0App クラス

Sample_App_with_Auth0App.swift
import SwiftUI

@main
struct Sample_App_with_Auth0App: App {
    @StateObject var service: Auth0Service = Auth0Service()
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(service)
        }
    }
}

ポイント

  • Auth0Service クラスのインスタンスを .environmentObject() を利用して他のクラスが isAuthenticated の値を取得できるようにしている。

ContentView クラス

ContentView.swift
import SwiftUI

struct ContentView: View {
    @EnvironmentObject var service: Auth0Service
    var body: some View {
        if service.isAuthenticated {
            HomeView()
        } else {
            LoginView()
        }
    }
}

ポイント

  • Auth0Service クラスの isAuthenticated の値に応じて表示する画面を切り替えている。

HomeView クラス

HomeView.swift
struct HomeView: View {
    @EnvironmentObject var service: Auth0Service
    
    var body: some View {
        VStack {
            userImage
            Text(service.userProfile.name)
                .padding()
            logoutButton
                .padding()
        }
    }
    
    private var userImage: some View {
        AsyncImage(url: URL(string: service.userProfile.picture)){ response in
            response.image?
                .resizable()
                .scaledToFit()
                .frame(width: 100,height: 100)
                .cornerRadius(50)
        }
    }
    
    private var logoutButton: some View {
        Button {
            logout()
        } label: {
            Text("Log out")
        }
        .fontWeight(.black)
        .frame(width: 160, height: 48)
        .foregroundColor(.white)
        .background(Color.primary)
        .cornerRadius(24)
    }
}


extension HomeView {
    private func logout() {
        service.logout()
    }
}

ポイント

  • ボタンを押すと logout() を実行し、具体的な処理を Auth0Service クラスに委任する

LoginView クラス

LoginView.swift
import SwiftUI

struct LoginView: View {
    @EnvironmentObject var service: Auth0Service
    
    var body: some View {
        VStack {
            title
            loginButton
        }
    }
    
    private var title: some View {
        Text("Welcome")
            .font(.largeTitle)
            .fontWeight(.black)
    }
    
    private var loginButton: some View {
        Button {
            login()
        } label: {
            Text("Log in")
        }
        .fontWeight(.black)
        .frame(width: 160, height: 48)
        .foregroundColor(.white)
        .background(Color.primary)
        .cornerRadius(24)
    }
}


extension LoginView {
    private func login() {
        service.login()
    }
}

ポイント

  • ボタンを押すと login() を実行し、具体的な処理を Auth0Service クラスに委任する

ポイント

ファイル Auth0 について

  • ファイル形式は .plist

image.png

Auth0 ファイルに関する設定

項目名 データ型 備考
Domain String Auth0 の Domain の値
ClientId String Auth0 の ClientId の値

image.png

注意事項

Auth0 のファイル名について
  • ファイル名は必ず Auth0 にすること。
  • Auth0.plist 等にするとエラーが発生する。
ClientId の項目名について
  • 項目名は必ず ClientId にすること。
  • ClientIDClientid 等で設定するとエラーが発生する。

参考資料

Auth0

YouTube

下記動画に手順がわかりやすく紹介されている。
英語ですが聞き取りやすいのでオススメです。

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