使ってみよう! Windows Live SDK/API

第40回Live Spaces API/SDK(2)─⁠─Live IDアカウントで認証

はじめに

今回も前回に引き続いてLive SpacesのAPI/SDKについてです。前回は、Live Spaces MetaWeblog APIを利用してブログへ記事の投稿をしました。その際に認証方法としてメール投稿用のユーザー名とパスワードを使用しましたが、今回はWindows Live IDアカウントを使用した認証を使ってみましょう。また、投稿以外の操作も行います。

クライアント認証

Windows Live IDアカウントによる認証方法は、チケットと呼ばれる文字列をWindows Live ID認証サーバーから取得して、そのチケットを利用して対象のLiveサービスにアクセスします図1⁠。今回対象となるLiveサービスはLive Spacesです。PC上で動作するクライアントアプリケーションでこのような認証を行うためにLive ID Client SDKという開発者ツールが提供されています。アプリケーションはこのSDKで提供されるサインイン ダイアログを利用してユーザー認証を行います。

図1 クライアント認証の仕組み
図1 クライアント認証の仕組み

今回はLive ID Client SDKを使用しますので下記を参考にインストールを行ってください。

開発環境

Live ID Client SDK

Live ID Client SDKは、ダウンロードページからWLIDClientSDK.msiをダウンロードしてインストールします。

インストーラーを実行すると、ライブラリーとサンプアプリケーションがインストールされます。通常、ライブラリーはC:\Program Files\Common Files\microsoft shared\WLIDClientにインストールされます(64bit Windowsの場合は、Program Files (x86)フォルダー⁠⁠。サンプルは、ドライブ直下にWLID Client Sampleフォルダーが作られ、実行ファイルとソースコードが配置されます。

64bit Windows環境にインストールする場合は少し注意が必要です。SDKのインストール後にサンプルアプリケーションが自動で起動しますが、このアプリケーションが64bitに対応していないため強制終了してしまいます。サンプルアプリケーションを確認するためには、サンプルのソースコードのプロジェクトをVisual Studioで開き、プロジェクトのプロパティからプラットフォームのターゲットをx86に指定し、ビルドしなおすことで可能です図2⁠。

図2 プラットフォームターゲットの指定
図2 プラットフォームターゲットの指定

プロジェクトの作成とライブラリーの参照

本記事ではVisual Studio 2010とVisual Basicを使用しますが、もちろんC#でもSDKは利用できます(SDK付属のサンプルはC#です⁠⁠。また、バージョンも2008で問題ありません。

まずは、コンソールアプリケーションなどの適当なWindowsプロジェクトを作成します。次に、ライブラリーの参照の追加をします。メニューの「プロジェクト」「参照の追加」を選択し、開いたウィンドウの.NETタブから「Microsoft.WindowsLive.Id.Client」を選びます。もしこの項目がない場合は、参照タブからSDKのインストール先から直接「Microsoft.WindowsLive.Id.Client.dll」を選択します。

サインイン処理

それでは、Live ID Client SDKを利用して、Windows Live IDアカウントを使用してLive Spacesにアクセスするためのコードを書いていきます。

最初にサインイン ダイアログ図3を表示してサインインを行うコードを記述します。サインインや認証処理はライブラリーに任せ、アプリケーションはダイアログ表示の呼び出しを行います。ユーザーは表示されたダイアログにWindows Live IDアカウントのメールアドレスとパスワードを入力しサインインすることになります。ユーザーの認証に成功した場合、サインインユーザーのメールアドレスなどは参照できますが、パスワード自体は参照できません。

図3 サインイン ダイアログ
図3 サインイン ダイアログ

この処理にはIdentityクラスとIdentityManagerクラスを使います。Identityクラスはユーザーを表します。Identityクラスのインスタンス生成にIdentityManagerクラスを使用します。Liveサービスの認証サーバーとのやりとりもIdentityManagerが使われます。Identityオブジェクトの作成とサインイン ダイアログの表示するコードは次のようになります。

' Imports Microsoft.WindowsLive.Id.Client と Import 宣言
' IdentityManager, Identity インスタンス生成
Dim manager = IdentityManager.CreateInstance("LiveSpacesSample;***@live.jp;Live Spaces Sample", "Live Spaces Sample")
Dim identity = manager.CreateIdentity

If Not identity.IsAuthenticated Then
    ' 認証されていない場合

    If identity.Authenticate Then ' ダイアログの表示
        ' (認証が成功した場合)
    Else
        ' (ユーザーによりキャンセルされた場合)
    End If
End If

IdentityManagerのインスタンスは、CreateInstanceメソッドにアプリケーションIDとアプリケーション名を渡すことで取得します。アプリケーションIDは、組織名・メールアドレス・アプリケーション名を「;」で区切った文字列です。IDの登録などの作業は必要なく、適切と思われる値を設定します。

Identityのインスタンスは、IdentityManager オブジェクトのCreateIdentityメソッドの戻り値として得ます。Identity オブジェクトのAuthenticateメソッドを呼び出すことでサインイン ダイアログが表示されます。

チケットの取得

サインインが完了し認証されている状態のとき、IdentityクラスのGetTicketメソッドを使用して特定のLiveサービスへのチケットの取得ができます。Live Spacesのアクセスに必要となるチケットを取得するコードは次のようになります。

' チケットの取得
Dim ticket = Identity.GetTicket("storage.msn.com", "MBI", True)

GetTicketメソッドの引数は、アクセス先・認証ポリシー・ローカルにキャッシュがある場合もサーバーからチケットを入手するか否かです。

このチケットの値を、HTTPのAuthorizationヘッダーに指定することで、Live Spaces MetaWeblog APIの場合、パスワードなしでアクセスが可能になります。

ここまでのコードをまとめると次のようになります。IdentityManagerオブジェクトとIdentityオブジェクトを格納する変数はPrivate変数に変更しています。サインイン関連の処理で例外が発生した場合、WLLogOnExceptionがスローされます。

Private Manager As IdentityManager
Private Identity As Identity
' Live Spaces アクセス用のチケットを返す
Function GetTicket() As String
    Try
        Manager = IdentityManager.CreateInstance("LiveSpacesSample;***@live.jp;Live Spaces Sample", "Live Spaces Sample")
        Identity = Manager.CreateIdentity
    Catch ex As WLLogOnException
        Throw
    End Try

    If Not Identity.IsAuthenticated Then
        If Identity.Authenticate Then
            Try
                ' チケットの取得
                Dim ticket = Identity.GetTicket("storage.msn.com", "MBI", True)
                Return ticket
            Catch ex As WLLogOnException
                Throw
            End Try
        Else
            ' Do nothing
        End If
    End If
    Return Nothing
End Function

実際にチケットを使用しているコードはこの後に紹介します。

カテゴリーの取得

さて前回はLive Spaces MetaWeblog APIを利用して記事の投稿を行いましたが、今回はまずカテゴリーの取得をしてみましょう。MetaWeblog APIについては前回の内容を参照してください。

新しい記事の投稿はmetaWeblog.getCategoriesメソッドを使用します。必要なパラメーターは次の通りです。

blogid ブログID
Live Spacesの場合自分のブログを表す「MyBlog」に固定
username ユーザー名
password パスワード

パスワードの値は、チケットによる認証を使用する場合、長さ0の文字列を指定します。

カテゴリー取得の場合、サーバーからは次のようなXMLが返ってきます。

<methodResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <params>
    <param>
      <value>
        <array>
          <data>
            <value>
              <struct>
                <member>
                  <name>description</name>
                  <value>Test Posts</value>
                </member>
                <member>
                  <name>htmlUrl</name>
                  <value />
                </member>
                <member>
                  <name>rssUrl</name>
                  <value />
                </member>
                <member>
                  <name>title</name>
                  <value>Test Posts</value>
                </member>
              </struct>
            </value>
            <value>
              <struct>
                <member>
                  <name>description</name>
                  <value>Books</value>
                </member>
                <member>
                  <name>htmlUrl</name>
                  <value />
                </member>
                <member>
                  <name>rssUrl</name>
                  <value />
                </member>
                <member>
                  <name>title</name>
                  <value>Books</value>
                </member>
              </struct>
            </value>
          </data>
        </array>
      </value>
    </param>
  </params>
</methodResponse>

カテゴリーの数だけ構造体を表す<struct>要素が含まれています。その中の、descriptionとtitleの両方カテゴリー名が格納されています。上記の場合、カテゴリー名はTest PostsとBooksです。

カテゴリーを取得するコードは次のようになります。

Sub GetCategories()

    ' パラメーター
    Dim blogId = "MyBlog" ' Live Spaces の場合 MyBlog で固定
    Dim userName = "***" ' Live Spaces の URL に含む文字列
    Dim password = "" ' 秘密のキーワード

    ' 要求時に送信するXML
    Dim requestXml =
        <?xml version="1.0" encoding="utf-8"?>
        <methodCall>
            <methodName>metaWeblog.getCategories</methodName>
            <params>
                <param><value><string><%= blogId %></string></value></param>
                <param><value><string><%= userName %></string></value></param>
                <param><value><string><%= password %></string></value></param>
            </params>
        </methodCall>

    ' 応答の受信
    Dim doc = GetResponse(requestXml)

    ' カテゴリーの列挙
    For Each m In doc...<member>
        If m.<name>.Value = "title" Then
            Console.WriteLine(m.<value>.Value)
        End If
    Next

End Sub

送信するXMLにはメソッド名としてmetaWeblog.getCategoriesが<methodName>要素に指定されているのがわかります。カテゴリーの列挙はtitleに指定されている値を表示するようにしています。XML文書を送信して応答を受信している部分のGetResponseメソッドは次のようになります。

Function GetResponse(ByVal requestXml As XDocument) As XDocument

    ' サービスエンドポイント
    Dim serviceEndpoint = "https://storage.msn.com/storageservice/MetaWeblog.rpc"

    ' XML を Byte 配列に変換
    Dim data() As Byte
    Using ms = New System.IO.MemoryStream
        requestXml.Save(ms)
        data = ms.ToArray
    End Using

    ' WebClient オブジェクトを作成し XML として送信
    Dim client = New WebClient
    client.Headers.Add(HttpRequestHeader.ContentType, "text/xml")

    ' ■ チケットを使用した認証 ■
    Dim ticket = GetTicket()
    client.Headers.Add(HttpRequestHeader.Authorization, "WLID1.0 " & ticket)

    ' XML の送信(記事の投稿)と応答の受信
    Dim responseData = client.UploadData(serviceEndpoint, data)
    Dim responseStream = New System.IO.MemoryStream(responseData)

    ' BOM(Byte Order Mark) がレスポンスの先頭についている場合、削除してから XML へ変換する必要がある
    Dim bom = System.Text.Encoding.UTF8.GetPreamble ' BOM
    Dim includesBom = True
    For Each b In bom
        If responseStream.ReadByte <> b Then
            includesBom = False
            responseStream.Seek(0, System.IO.SeekOrigin.Begin)
            Exit For
        End If
    Next

    ' XDocument に変換
    Dim doc As XDocument
    If includesBom Then
        Dim buf(Convert.ToInt32(responseStream.Length - bom.Length - 1)) As Byte
        For i = 0 To buf.Length - 1
            buf(i) = CByte(responseStream.ReadByte)
        Next
        doc = XDocument.Parse(System.Text.Encoding.UTF8.GetString(buf))
    Else
        doc = XDocument.Parse(System.Text.Encoding.UTF8.GetString(responseStream.ToArray))
    End If

    responseStream.Close()
    Return doc

End Function

上記コードの多くの部分は、前回の記事投稿のコードと同じです。異なる部分はチケットを使用した認証部分です。先ほど示したGetTicketメソッドからチケットを取得し、WebClientオブジェクトのリクエストヘッダーにチケットの値を指定しています。次のようにHTTP Authorizationヘッダーには、チケットの値の前に「WLID1.0」を付ける必要があります。

Authorization: WLID1.0 ticket_data

ここまでを実行して正しくカテゴリーが取得できたでしょうか? 指定しているパラメーターなどが誤っている場合、サーバーからはエラー内容が記述されたXMLが応答されますので、その内容を確認して対処します。

記事の取得と編集

カテゴリーの取得以外に、MetaWeblog APIを利用して次の操作もしてみましょう。

  • 最近投稿したブログの記事や下書きの記事一覧の取得
  • 指定した記事の取得
  • 記事の編集

最近の記事一覧の取得

最近投稿した下書きを含む記事を取得してみましょう。前回紹介したmetaWeblog.newPost メソッドによる記事の投稿では、投稿に成功した場合、記事のIDを戻り値として受信していました。このように投稿した記事には ひとつひとつIDが付いています。このIDは、最近の記事一覧を取得することでも各IDがわかります。

最近の記事一覧の取得は、metaWeblog.getRecentPostsメソッドを使います。パラメーターは次の通りです。

blogid ブログID
Live Spacesの場合自分のブログを表す「MyBlog」に固定
username ユーザー名
password パスワード
numberOfPosts 取得する記事数(最大20)

戻り値、つまりサーバーからの応答には次の情報が、記事の数だけ含まれています。

title 記事のタイトル
description 記事の本文
postid 記事のID
dateCreated 投稿日時
categories 記事のカテゴリーの配列
publish 記事が公開済みの場合1、下書きの場合0

実際のコードは次のようになります。

Sub GetRecentPosts()

    ' パラメーター
    Dim blogId = "MyBlog" ' Live Spaces の場合 MyBlog で固定
    Dim userName = "***" ' Live Spaces の URL に含む文字列
    Dim password = "" ' 秘密のキーワード
    Dim numberOfPosts = 20 ' 取得する記事数(最大20)

    ' 要求時に送信するXML
    Dim requestXml =
        <?xml version="1.0" encoding="utf-8"?>
        <methodCall>
            <methodName>metaWeblog.getRecentPosts</methodName>
            <params>
                <param><value><string><%= blogId %></string></value></param>
                <param><value><string><%= userName %></string></value></param>
                <param><value><string><%= password %></string></value></param>
                <param><value><i4><%= numberOfPosts %></i4></value></param>
            </params>
        </methodCall>

    ' 応答の受信
    Dim doc = GetResponse(requestXml)

End Sub

指定した記事の取得

記事の投稿や最近の記事一覧の取得などにより記事のIDがわかれば、メソッドを使用して、特定のひとつの記事の情報のみ取得できます。パラメーターは次の通りです。これまでと違い、blogidには記事のIDを指定します。

blogid 記事のID
username ユーザー名
password パスワード

戻り値は、指定したIDの記事の情報です。取得できる項目は、metaWeblog.getRecentPostsメソッドを呼び出したときと同じです。

コードは次のようになります。

Sub GetPost()

    ' パラメーター
    Dim blogId = "xxx" ' 取得する記事のID (getRecentPosts で取得できる postid)
    Dim userName = "***" ' Live Spaces の URL に含む文字列
    Dim password = "" ' 秘密のキーワード

    ' 要求時に送信するXML
    Dim requestXml =
        <?xml version="1.0" encoding="utf-8"?>
            <methodCall>
                <methodName>metaWeblog.getPost</methodName>
                <params>
                    <param><value><string><%= blogId %></string></value></param>
                    <param><value><string><%= userName %></string></value></param>
                    <param><value><string><%= password %></string></value></param>
                </params>
            </methodCall>

    ' 応答の受信
    Dim doc = GetResponse(requestXml)

End Sub

記事の編集

今回の最後は記事の編集です。記事の編集、つまり既に投稿済みの記事の更新は、metaWeblog.editPostメソッドを使います。パラメーターは以下のものがあります。これらの項目は、metaWeblog.newPostメソッドのものと同じです。blogidに指定する値が、ブログIDか記事のIDかで異なっています。

blogid 記事のID
username ユーザー名
password パスワード
content 記事の情報の構造体
publish 公開する場合1、下書きにする場合0

content構造体の項目は次の通りです。

title 記事のタイトル
description 記事の本文
dateCreated 投稿日時
categories 記事のカテゴリーの配列

正常に処理が完了したときの戻り値は、次のXMLが返ってきます。常にtrueを返します。

<methodResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <params>
    <param>
      <value>
        <boolean>1</boolean>
      </value>
    </param>
  </params>
</methodResponse>

コードは次のようになります。

Sub EditPost()

    ' パラメーター
    Dim blogId = "xxx" ' 取得する記事のID (getRecentPosts で取得できる postid)
    Dim userName = "***" ' Live Spaces の URL に含む文字列
    Dim password = "" ' 秘密のキーワード
    Dim publish = True ' 投稿 True / 下書き False
    Dim categories = New List(Of String) From {"Books"} ' カテゴリー(Live Spaces はひとつのカテゴリー指定しか対応していません)

    ' content 構造体に指定する項目
    Dim title = "編集したタイトル" ' 記事タイトル
    Dim description = "編集した本文" ' 記事の本文
    Dim dateCreated = DateTime.UtcNow ' 投稿日時

    ' 要求時に送信するXML
    Dim requestXml =
        <?xml version="1.0" encoding="utf-8"?>
        <methodCall>
            <methodName>metaWeblog.editPost</methodName>
            <params>
                <param><value><string><%= blogId %></string></value></param>
                <param><value><string><%= userName %></string></value></param>
                <param><value><string><%= password %></string></value></param>
                <param>
                    <value>
                        <struct>
                            <member>
                                <name>title</name>
                                <value><string><%= title %></string></value>
                            </member>
                            <member>
                                <name>description</name>
                                <value><string><%= description %></string></value>
                            </member>
                            <member>
                                <name>categories</name>
                                <value>
                                    <array>
                                        <%= From c In categories
                                            Select <data><value><string><%= c %></string></value></data>
                                        %>
                                    </array>
                                </value>
                            </member>
                            <member>
                                <name>dateCreated</name>
                                <value><dateTime.iso8601><%= dateCreated.ToString("s") %></dateTime.iso8601></value>
                            </member>
                        </struct>
                    </value>
                </param>
                <param><value><boolean><%= If(publish, 1, 0) %></boolean></value></param>
            </params>
        </methodCall>

    ' 応答の受信
    Dim doc = GetResponse(requestXml)

    ' ブログへ移動
    Process.Start("http://" & userName & ".spaces.live.com/blog/cns!" & blogId & ".entry")

End Sub

今回は以上です。前回の内容とあわせると、Live Spacesのブログ投稿や編集を行う自作クライアントソフトの作成もできますね。次回ももう少しLive Spacesについて扱う予定です。

おすすめ記事

記事・ニュース一覧