iOSアプリでSharePoint Onlineにサインインする方法

アドバンスド · ソリューション株式会社 平田貴嗣


SharePoint Onlineに対して、iOSアプリからRESTなどで通信する場合に必要になるのが認証です。

このTipsでは、iOSアプリでSharePoint Onlineに認証するために、どのような実装を行えばよいかを説明します。

 

■処理の概要

Microsoft/組織アカウントでの認証では、ネイティブのiOSアプリから認証を行う場合でも、WEBブラウザーを介した認証処理を行います。

ネイティブのiOSアプリでは、コンポーネントとして、UIWebViewというブラウザーコンポーネントが用意されていますので、これを利用して認証処理を行います。UIWebViewは、iOSアプリ内で、ローカルのHTMLを表示したり、外部のWebサイトを表示することができるコンポーネントです。

認証に際し、UIWebViewの中でSharePoint Onlineのサインインページをそのまま開き、ユーザーはそのページ内でアカウント情報を入力してサインインをします。

サインインを行うと、iOSアプリのソースコードにおいてUIWebViewのページ遷移イベント内で認証トークン(HTTPクッキー)を受け取ることができます。

認証トークンは、RESTで通信をする際に必要となりますので、iOSアプリ内で保持します。

   

■画面の作成

では、まず画面についてです。

今回の説明におけるiOSアプリの画面の構成は、下記の通りです。

  1. MainViewController ← メイン画面(サインインを行わないと使用できない画面)です。
  2. SigninViewController ← SharePoint OnlineのサインインページをUIWebViewで表示するサインイン画面です。


本Tipsでは、サインインを行うためのSigninViewControllerの画面はモーダルで表示します。

MainViewController以外の画面からも汎用的に呼び出せるように、SigninViewControllerにはStoryboard IDを割り振っておくとよいでしょう。

StoryboardのSegueではなく、Storyboard IDで画面を呼び出せるように実装することにより、例えば認証トークンとして受け取るHTTPクッキーの期限が切れて再サインインが必要となった場合でも、どこの画面からもSigninViewControllerの画面が呼び出させるようになります。

 

Storyboardでの画面構成)

 

 

■ソースコードの作成

次は、実装するソースコードについてです。

   

今回の説明で使用するソースファイルの構成は、下記の通りです。

  1. SigninViewController.swift ← サインイン画面のソースコードです。
  2. MainViewConroller.swift ← メイン画面のソースコードです。


SigninViewControllerのviewDidLoadメソッド内で、SharePoint OnlineのサインページをUIWebViewで表示します。

ユーザーがサインインページでサインインを行うと、UIWebViewのデリゲートメソッドであるページ遷移メソッドがコールバックで呼び出されますので、その中で認証トークンを取得してください。

       let cookies = NSHTTPCookieStorage.sharedHTTPCookieStorage().cookies

        for cookie: NSHTTPCookie in cookies as Array {

            if (cookie.name == "FedAuth") {

                self.fedAuthCookie = cookie;

                continue;

            }

            if (cookie.name == "rtFa") {

                self.rtFaCookie = cookie;

                continue;

            }

        }

取得できた場合、正常にサインインができたということになります。

SharePoint Onlineで使用する認証トークンは、「FedAuth」 と 「rtFa」という名前のHTTPクッキーになります。

本TipsのMainViewControllerでは、画面表示時に認証トークンの存在チェックを行い、認証トークンが存在しない場合にSigninViewControllerをモーダルで呼び出すように実装しています。

 

また、本サンプルコードでは処理を省略していますが、UIWebViewでSharePoint Onlineのサインインページを読み込んでいる間は、ユーザーに読み込み中であることが視覚的に分かるように、ローディング表示をするとよいかと思います。

   

下記は、コーディング例になります。

サンプルコード)

SigninViewController.swift

//

//  SigninViewController.swift

//

import UIKit

 

// 認証結果を返すためのデリゲート

protocol SigninDelegate {

    func didSignin(#rtFaCookie: NSHTTPCookie, fedAuthCookie: NSHTTPCookie)

}

 

// サインイン画面

class SigninViewController: UIViewController, UIWebViewDelegate {

      

    // UIWebView

    @IBOutlet weak var webView: UIWebView!

      

    // rtFAクッキー

    var rtFaCookie: NSHTTPCookie!

      

    // FedAuthクッキー

    var fedAuthCookie: NSHTTPCookie!

      

    // 認証結果を返すためのデリゲート

    var delegate: SigninDelegate!

 

    override func viewDidLoad() {

        super.viewDidLoad()

 

        // SharePoint Onlineのサインイン画面を開く

        var url = NSURL(string: "https://xxx.sharepoint.com/_layouts/15/authenticate.aspx?Source=/")

        var urlRequest = NSURLRequest(URL: url!)

 

        self.webView.delegate = self

        self.webView.loadRequest(urlRequest)

    }

 

    override func didReceiveMemoryWarning() {

        super.didReceiveMemoryWarning()

        // Dispose of any resources that can be recreated.

    }

 

    // ページの読み込みが開始された場合のコールバックイベント

    func webViewDidStartLoad(webView: UIWebView!) {

        // 認証情報のチェック

        self.verify()

    }

      

    // ページが読み込みが完了した場合のコールバックイベント

    func webViewDidFinishLoad(webView: UIWebView!) {

        // 認証情報のチェック

        self.verify()

    }

      

    // 認証情報をチェックするメソッド

    func verify() {

        // UIWebViewを非表示に設定

        self.webView.hidden = true

          

        // 認証済みかクッキーを確認

        let cookies = NSHTTPCookieStorage.sharedHTTPCookieStorage().cookies

          

        for cookie: NSHTTPCookie in cookies as Array {

            if (cookie.name == "FedAuth") {

                self.fedAuthCookie = cookie;

                continue;

            }

            if (cookie.name == "rtFa") {

                self.rtFaCookie = cookie;

                continue;

            }

        }

          

        // 認証済みであればサインイン画面を閉じる

        if self.rtFaCookie != nil && self.fedAuthCookie != nil {

              

            // 認証結果を元の画面に返す

            self.delegate.didSignin(

                                rtFaCookie: self.rtFaCookie,

                                fedAuthCookie: self.fedAuthCookie

                            )

              

            // 画面を閉じる

            self.dismissViewControllerAnimated(true, completion: nil)

              

        } else {

            // UIWebViewの非表示を解除

            self.webView.hidden = false

        }

    }

 

}

 

 

MainViewController.swift

//

//  MainViewController.swift

//

import UIKit

 

class MainViewController: UIViewController, SigninDelegate {

 

    // rtFAクッキー

    var rtFaCookie: NSHTTPCookie!

      

    // FedAuthクッキー

    var fedAuthCookie: NSHTTPCookie!

      

    override func viewDidLoad() {

        super.viewDidLoad()

    }

      

    override func viewDidAppear(animated: Bool) {

        // 認証情報がない場合はサインイン画面に遷移

        if self.rtFaCookie == nil || self.fedAuthCookie == nil {

            if var storyboard = self.storyboard {

                var signinViewController = storyboard.instantiateViewControllerWithIdentifier("Signin") as SigninViewController

                signinViewController.delegate = self

                  

                self.presentViewController(signinViewController, animated: false, completion: nil);

            }

        }

    }

 

    override func didReceiveMemoryWarning() {

        super.didReceiveMemoryWarning()

    }

      

    // 認証結果を受け取る

    func didSignin(#rtFaCookie: NSHTTPCookie, fedAuthCookie: NSHTTPCookie) {

        self.rtFaCookie = rtFaCookie

        self.fedAuthCookie = fedAuthCookie

    }

}

 

以上になります。