Blog スタッフブログ

iOS PHP Swift システム開発

[Swift]AuthenticationServicesでoAuth認証を実装してみた

Swift

こんにちは、株式会社MIXシステム開発担当のBloomです。

早速本題のAuthenticationServicesでoAuth認証を実装する手順について、

お仕事の中で得た知見を共有させていただきたいと思います。

AuthenticationServicesとは

AuthenticationServicesフレームワークは主に認証情報を入力しログインをする際の操作をサポートしてくれます。

Sign in with Appleの実装に主に使われています(当社比)が、Web上で行うoAuth認証にアプリからアクセスする際、コールバックでトークンを受け取りたい場合に利用することができます。

今回は例として実際にLINEログインを実装して動作を見てみましょう。

※LINEログインはiOS版SDKも公開されているため、実際は他のアプリネイティブSDKを提供していないoAuth認証サービスで利用してください。

Web側コールバックAPI実装

LINE Developersへの登録は割愛させていただきます。今回は審査不要なprofileスコープのみのリクエストとします。

<?php
if (isset($_REQUEST['code'])) {
    $code = $_REQUEST['code'];
    $result = getToken($code);
    $res_array = json_decode($result);
    // アプリ側で設定するコールバックスキームをプロトコルに指定
    $uri = "sandbox://auth?token=".$res_array->access_token;
    echo <<< EOM
    <!DOCTYPE html>
    <html>
    <head><meta charset="utf-8">
    <script type="text/javascript">
    window.onload = function(){
        // 直接アプリ側で設定するコールバックスキームへリダイレクト
        location.href= "{$uri}";
    }
    </script>
    </head>
    <body>
    // 直接コールバックさせなくてもリンク押下で遷移もできます。
    <a href="{$uri}">ログイン</a>
    </body></html>
EOM;
}

// curlでアクセストークンを取得
function getToken($code) {
    $header_array = array(
    "Content-Type: application/x-www-form-urlencoded"
    );
    $data_array = 
    array("grant_type" => "authorization_code",
    "code" => $code,
    "redirect_uri" => "[LINE Developersコンソールで指定したリダイレクトURI]",
    "client_id" => "[LINE Developersコンソールで確認できるチャネルID]",
    "client_secret" => "[LINE Developersコンソールで確認できるチャネルシークレット]"
    );
    $data = http_build_query($data_array , "" , "&");

    $curl = curl_init();
    curl_setopt($curl , CURLOPT_HTTPHEADER , $header_array);
    curl_setopt($curl , CURLOPT_URL , "https://api.line.me/oauth2/v2.1/token");
    curl_setopt($curl , CURLOPT_RETURNTRANSFER , 1);
    curl_setopt($curl , CURLOPT_HTTP_VERSION , CURL_HTTP_VERSION_1_1);
    curl_setopt($curl , CURLOPT_CUSTOMREQUEST , 'POST');
    curl_setopt($curl , CURLOPT_POSTFIELDS , $data);
    $result = curl_exec($curl);
    if(curl_errno($curl)){
        $error = curl_error($curl);
        var_dump($error);
    }
    curl_close($curl);

    return $result;
}
?>

iOS側実装

import AuthenticationServices
class ViewController: UIViewController {
    @IBOutlet weak var tokenLabel: UILabel!
    // 今回はログインボタンの押下に反応してログインさせます
    @IBAction func login(_ sender: Any) {
        let endpoint = "https://access.line.me/oauth2/v2.1/authorize?"
        let response_type = "code"
        let client_id = "[LINE Developersコンソールで確認できるチャネルID]"
        let redirect_uri = "[LINE Developersコンソールで設定したリダイレクトURI]".addingPercentEncoding(withAllowedCharacters: .alphanumerics)!
        let state = "[CSRF対策のランダム文字]"
        let scope = "profile"
        let urlString = "\(endpoint)response_type=\(response_type)&client_id=\(client_id)&redirect_uri=\(redirect_uri)&state=\(state)&scope=\(scope)"
        
        let url = URL(string: urlString)!

        let session = ASWebAuthenticationSession(url: url,
                                                 callbackURLScheme: "sandbox") { callbackURL, error in
            if error != nil {
                print(error.debugDescription)
            }
            
            if callbackURL != nil {
                let queryItems = URLComponents(string: callbackURL!.absoluteString)?.queryItems
                let token = queryItems?.filter( {$0.name == "token"} ).first?.value ?? ""
                print(token)
                if !token.isEmpty {
                    self.tokenLabel.text = "アクセストークンを取得できました"
                }
            }
        }
        // prefersEphemeralWebBrowserSessionで前回入力を引き継ぐかどうか指定可能です。
        session.prefersEphemeralWebBrowserSession = false
        session.presentationContextProvider = self
        // ブラウザ起動
        session.start()
    }
}
extension ViewController: ASWebAuthenticationPresentationContextProviding {
    func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
        return self.view.window!
    }
}

実行結果

これで簡単にoAuth認証のアクセストークンの取得ができました。良かったですね。

参考文献

Webサービスを通してユーザーを認証する – Apple Developers

LINEログイン v2.1 APIリファレンス – LINE Developers