アドバンスド · ソリューション株式会社 平田貴嗣
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アプリの画面の構成は、下記の通りです。
- MainViewController ← メイン画面(サインインを行わないと使用できない画面)です。
- SigninViewController ← SharePoint OnlineのサインインページをUIWebViewで表示するサインイン画面です。
本Tipsでは、サインインを行うためのSigninViewControllerの画面はモーダルで表示します。
MainViewController以外の画面からも汎用的に呼び出せるように、SigninViewControllerにはStoryboard IDを割り振っておくとよいでしょう。
StoryboardのSegueではなく、Storyboard IDで画面を呼び出せるように実装することにより、例えば認証トークンとして受け取るHTTPクッキーの期限が切れて再サインインが必要となった場合でも、どこの画面からもSigninViewControllerの画面が呼び出させるようになります。
Storyboardでの画面構成)
■ソースコードの作成
次は、実装するソースコードについてです。
今回の説明で使用するソースファイルの構成は、下記の通りです。
- SigninViewController.swift ← サインイン画面のソースコードです。
- 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
}
}
以上になります。