[.NET][OAuth Series] EasyOAuth Library for Web Application

自昨天首發 EasyOAuth Library for Desktop Application 後,今天再進一步發表 EasyOAuth Library for Web Application,這個函式庫可以支援 ASP.NET 與 ASP.NET MVC 應用程式開發支援 OAuth 功能的 Web 應用程式,它一樣可以在少量程式開發的情況下讓 Web 應用程式支援 OAuth 的功能,並且與 EasyOAuth Library for Desktop Application 一樣,可支援 Google, Facebook, Yahoo 與 Twitter 四種內建的 OAuth Service Provider。

EasyOAuth

自昨天首發 EasyOAuth Library for Desktop Application 後,今天再進一步發表 EasyOAuth Library for Web Application,這個函式庫可以支援 ASP.NET 與 ASP.NET MVC 應用程式開發支援 OAuth 功能的 Web 應用程式,它一樣可以在少量程式開發的情況下讓 Web 應用程式支援 OAuth 的功能,並且與 EasyOAuth Library for Desktop Application 一樣,可支援 Google, Facebook, Yahoo 與 Twitter 四種內建的 OAuth Service Provider。

為什麼要特別分開 EasyOAuth Library 為 Desktop 版本和 Web 版本?主要原因是 Desktop 版本和 Web 版本在進行認證的程序上會有不同,Desktop 是透過應用程式自己打開瀏覽器的方式,由使用者自己提供授權碼來認證,但 Web 應用程式不需要使用者提供授權碼這一段,OAuth Service Provider 會自動回呼 (callback) Web 應用程式所提供的 callback URL 並做後續處理,且基於 Web 應用程式無法保持狀態的模型,所以 Web 版本的 EasyOAuth Library 需要以 Web 環境來設計,故不能將兩個 Library 放在一起。

EasyOAuth Library for Web Application 的使用也很簡單,首先與 EasyOAuth Library for Desktop Application 一樣,要先取得 OAuth Service Provider 所發給的 consumer key 與 consumer secret,然後開啟 Web 專案,並在 Web.config 中的 <configSections> 中加入:

<configSections>
  <section name="oauth.configuration" type="OAuth.Web.OAuthWebConfigurationSection, OAuth.Web"/>
</configSections>

然後加入下面的組態設定:

<oauth.configuration defaultPersistProvider="DB" verifyHandler="OAuthVerifyHandler.do" userAcceptedHandler="Result.aspx" userDeniedHandler="Result.aspx">
  <providers>
    <add provider="GoogleAccount" assembly="OAuth.Web" type="OAuth.Web.GoogleOAuthProvider"
          consumerKey="" consumerSecret=""
          scope="
https://www.google.com/base/feeds/ http://gdata.youtube.com/feeds/api/videos/"
          consentUrl="https://www.google.com/accounts/OAuthAuthorizeToken"
          requestTokenUrl="https://www.google.com/accounts/OAuthGetRequestToken"
          requestAccessTokenUrl="https://www.google.com/accounts/OAuthGetAccessToken"
          callback="http://[your_url]/OAuthVerifyHandler.do"/>
    <add provider="Yahoo" assembly="OAuth.Web" type="OAuth.Web.YahooOAuthProvider"
          consumerKey="" consumerSecret="" scope=""
          consentUrl="
https://api.login.yahoo.com/oauth/v2/request_auth"
          requestTokenUrl="https://api.login.yahoo.com/oauth/v2/get_request_token"
          requestAccessTokenUrl="https://api.login.yahoo.com/oauth/v2/get_token"
          callback="http://[your_url]/OAuthVerifyHandler.do"/>
    <add provider="Twitter" assembly="OAuth.Web" type="OAuth.Web.TwitterOAuthProvider"
          consumerKey="" consumerSecret="" scope=""
          consentUrl="
http://api.twitter.com/oauth/authorize"
          requestTokenUrl="https://api.twitter.com/oauth/request_token"
          requestAccessTokenUrl="https://api.twitter.com/oauth/access_token"
          callback="http://[your_url]/OAuthVerifyHandler.do"/>
    <add provider="Facebook" assembly="OAuth.Web" type="OAuth.Web.FacebookOAuthProvider"
          consumerKey="" consumerSecret="" scope="publish_stream,read_stream,email,offline_access"
          consentUrl="
https://www.facebook.com/dialog/oauth?client_id={0}&amp;redirect_uri={1}&amp;scope={2}"
          callback="http://[your_url]/OAuthVerifyHandler.do"
          requestTokenUrl=""
          requestAccessTokenUrl="
https://graph.facebook.com/oauth/access_token?client_id={0}&amp;redirect_uri={1}&amp;client_secret={2}&amp;code={3}"/>
  </providers>
  <persists>
    <add name="DB" provider="OAuth.PersistDBProvider" connectionString=""/>
    <add name="XML" provider="OAuth.PersistXmlProvider" connectionString=""/>
  </persists>
</oauth.configuration>

欄位值說明如下:

  • verifyHandler: 當 OAuth Service Provider 進行回呼時,負責處理的 Verify Handler,預設為 OAuthVerifyHandler.do,使用的是內建的 OAuth.Web.OAuthVerifyHandler 類別。
  • userAcceptedHandler: 使用者允許授權時,要接手處理的 URL,可以是 ASP.NET Web Form 或 MVC Controller Path。
  • userDeniedHandler: 使用者拒絕授權時,要接手處理的 URL,可以是 ASP.NET Web Form 或 MVC Controller Path。
  • consumerKey: 由 OAuth Service Provider 提供的 consumer key。
  • consumerSecret: 由 OAuth Service Provider 提供的 consumer secret。
  • scope: 應用程式要求使用者授權的範圍,每個 OAuth Service Provider 的定義不同,請參考各 Service Provider 的文件。
  • consentUrl: OAuth Service Provider 向使用者要求授權的 URL。
  • requestTokenUrl: 應用程式向 OAuth Service Provider 要求識別符記 (request token) 的 URL。
  • requestAccessTokenUrl: 應用程式向 OAuth Service Provider 要求存取符記 (access token) 的 URL。
  • callback: OAuth Service Provider 向使用者要求授權結束時,回呼的應用程式 URL,在 Web Application 中為必要項。

完成 OAuth 的基本設定後,要再加入一個 OAuth Verify Handler 的設定,這個設定是在 IIS 上掛載 HTTP Handler 的指令,以 IIS 7 來說,要在 Web.config 的 <system.webServer> 區中加入:

<system.webServer>
  <handlers>
    <add name="OAuthWebVerifier" preCondition="integratedMode" verb="GET" path="OAuthVerifyHandler.do" type="OAuth.Web.OAuthVerifiyHandler"/>
  </handlers>
</system.webServer>

若是 IIS 6.0,則是:

<system.web>
  <httpHandlers>
    <add path="OAuthVerifyHandler.do" type="OAuth.Web.OAuthVerifiyHandler" verb="GET"/>
  </httpHandlers>
</system.web>

設定完成後,回到 Web 專案,將 OAuth.dll 與 OAuth.Web.dll 加入參考後,於登入的入口處,加入呼叫 OAuthContext 的程式碼:

OAuth.Web.OAuthContext context = new OAuth.Web.OAuthContext(OAuth.OAuthProviderType.Twitter);

try
{
    if (!context.IsAccessTokenValid("1111"))
    {
        context.ObtainRequestToken();
        context.ObtainVerifier();
    }
}
catch (OAuthUnauthorizedException ex)
{
    Response.Write(string.Format(
        "Exception: {0}<br />Message: {1}<br />Signature: {2}<br />Base String: {3}<br />Header: {4}<br />Responsen Data: {5}",
        "OAuthUnauthorizedException", ex.Message, ex.Signature, ex.SignatureBaseString, ex.AuthorizationHeader, ex.ResponseDataString));
}

接著,新增處理 OAuth 回呼的網頁 (於 userAcceptedHandler 與 userDeniedHandler 指定的)。成功的話,可以由 OAuthContext.Current 中取得使用者的 access token,若失敗,則可由 Session["OAuthUserDeniedMessage"] 取得失敗的訊息字串:

OAuth.Web.OAuthContext context = OAuth.Web.OAuthContext.Current;

if (string.IsNullOrEmpty(context.Provider.GetDataRepository().Token))
{
    this.labelResultData.Text = "Unauthorized.";
    Session.Remove("OAuthUserDeniedMessage");
}
else
{
    this.labelResultData.Text = string.Format("User authorized, token: {0}", context.Provider.GetDataRepository().Token);
}

使用者的操作程序也很簡單,只要進入登入頁:

image

按下其中一個項目,會自動導向到 OAuth Service Provider 的授權要求頁:

image

授權完成後,會導向到 userAcceptedHandler 設定的頁面,本例會顯示出取得的 access token 的字串:

image

在 EasyOAuth Library for Web Application 的下載頁的 source code 中,有一個 OAuth.Web.Client 的範例程式,可參考此程式以取得 EasyOAuth Library for Web Application 的使用方式。