2010-03-08 94 views

回答

2

它不是最簡單的東西來解釋,但我這樣做是爲特定的YouTube實現:

我建了一個ShardOAuth類構建消息:

#Region "Imports" 
Imports System.Text 
Imports System.Security.Cryptography 
#End Region 

Public NotInheritable Class SharedOAuth 

#Region "Class Declarations" 
    Private Const unreservedChars As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.~" 

    Private Const OAuthVersion As String = "1.0" 
    Private Const OAuthParameterPrefix As String = "oauth_" 
    Private Const OAuthParameterExclusionPrefix As String = "xoauth_" 

    Private Const OAuthConsumerKeyKey As String = "oauth_consumer_key" 
    Private Const OAuthCallbackKey As String = "oauth_callback" 
    Private Const OAuthVersionKey As String = "oauth_version" 
    Private Const OAuthSignatureMethodKey As String = "oauth_signature_method" 
    Private Const OAuthSignatureKey As String = "oauth_signature" 
    Private Const OAuthTimestampKey As String = "oauth_timestamp" 
    Private Const OAuthNonceKey As String = "oauth_nonce" 
    Private Const OAuthTokenKey As String = "oauth_token" 
    Private Const OAuthTokenSecretKey As String = "oauth_token_secret" 
#End Region 

#Region "Constructor" 
    Private Sub New() 
     'prevent construction 
    End Sub 
#End Region 


#Region "Shared Functions" 
    Public Shared Function GetSignatureTypeNameFromType(ByVal signatureType As enumerations.OAuthEnumerations.SignatureTypes) As String 
     Select Case signatureType 
      Case enumerations.OAuthEnumerations.SignatureTypes.HmacSha1 
       Return "HMAC-SHA1" 
      Case Else 
       Return String.Empty 
     End Select 
    End Function 

    Public Shared Function GenerateTimeStamp() As String 
     'Implementation of UNIX current UTC time 
     Dim _ts As TimeSpan = DateTime.UtcNow - New DateTime(1970, 1, 1, 0, 0, 0, 0) 
     Return Convert.ToInt64(_ts.TotalSeconds).ToString(CultureInfo.InvariantCulture) 
    End Function 

    Public Shared Function GenerateNonce() As String 
     'Some random Number 
     Return New Random().Next(123400, 9999999).ToString 
    End Function 

    Public Shared Function UrlEncode(ByVal value As String) As String 
     Dim _result As New StringBuilder 

     If (String.IsNullOrEmpty(value)) Then 
      Return value 
     End If 

     For Each _symbol As Char In value 
      If unreservedChars.IndexOf(_symbol) <> -1 Then 
       _result.Append(_symbol) 
      Else 
       _result.Append(String.Format("%{0}", String.Format("{0:X2}", Asc(_symbol)))) 
      End If 
     Next 

     Return _result.ToString 
    End Function 

    ''' <summary> 
    '''Generates a signature using the specified signatureType 
    ''' </summary>  
    ''' <param name="url">The full url that needs to be signed including its non OAuth url parameters</param> 
    ''' <param name="consumerKey">The consumer key</param> 
    ''' <param name="consumerSecret">The consumer seceret</param> 
    ''' <param name="token">The token, if available. If not available pass null or an empty string</param> 
    ''' <param name="tokenSecret">The token secret, if available. If not available pass null or an empty string</param> 
    ''' <param name="httpMethod">The http method used. Must be a valid HTTP method verb (POST,GET,PUT, etc)</param> 
    ''' <param name="signatureType">The type of signature to use</param> 
    ''' <returns>A base64 string of the hash value</returns> 
    Public Shared Function GenerateSignature(ByVal url As Uri, ByVal consumerKey As String, ByVal consumerSecret As String, ByVal token As String, ByVal tokenSecret As String, ByVal httpMethod As String, ByVal timeStamp As String, ByVal nonce As String, ByVal signatureType As enumerations.OAuthEnumerations.SignatureTypes, ByRef normalizedUrl As String, ByRef normalizedRequestParameters As String) As String 
     normalizedUrl = String.Empty 
     normalizedRequestParameters = String.Empty 

     Dim _signatureBase As String 
     Dim _hash As HMACSHA1 

     Select Case signatureType 
      Case enumerations.OAuthEnumerations.SignatureTypes.HmacSha1 
       _signatureBase = GenerateSignatureBase(url, consumerKey, token, tokenSecret, httpMethod, timeStamp, nonce, enumerations.OAuthEnumerations.SignatureTypes.HmacSha1, normalizedUrl, normalizedRequestParameters) 

       Dim _sb As New StringBuilder 
       With _sb 
        .Append(UrlEncode(consumerSecret)) 
        .Append("&") 

        If (String.IsNullOrEmpty(tokenSecret)) Then 
         .Append("") 
        Else 
         .Append(UrlEncode(tokenSecret)) 
        End If 
       End With 

       _hash = New HMACSHA1 
       _hash.Key = Encoding.ASCII.GetBytes(_sb.ToString) 

       Return GenerateSignatureUsingHash(_signatureBase, _hash) 

      Case Else 
       Throw New NotImplementedException 

     End Select 
    End Function 

    Public Shared Function GenerateSignatureUsingHash(ByVal signatureBase As String, ByVal hash As HashAlgorithm) As String 
     Return ComputeHash(hash, signatureBase) 
    End Function 

    Public Shared Function GenerateSignatureBase(ByVal url As Uri, ByVal consumerKey As String, ByVal token As String, ByVal tokenSecret As String, ByVal httpMethod As String, ByVal timeStamp As String, ByVal nonce As String, ByVal signatureType As enumerations.OAuthEnumerations.SignatureTypes, ByRef normalizedUrl As String, ByRef normalizedRequestParameters As String) As String 
     Dim _SignatureTypeName As String = GetSignatureTypeNameFromType(signatureType) 

     If String.IsNullOrEmpty(token) Then 
      token = String.Empty 
     End If 

     If String.IsNullOrEmpty(tokenSecret) Then 
      tokenSecret = String.Empty 
     End If 

     If String.IsNullOrEmpty(consumerKey) Then 
      Throw New ArgumentNullException("consumerKey") 
     End If 

     If String.IsNullOrEmpty(httpMethod) Then 
      Throw New ArgumentNullException("httpMethod") 
     End If 

     If String.IsNullOrEmpty(_SignatureTypeName) Then 
      Throw New ArgumentNullException("SignatureType") 
     End If 

     normalizedUrl = String.Empty 
     normalizedRequestParameters = String.Empty 

     Dim _params As List(Of QueryParameter) = getqueryparameters(url.Query) 

     With _params 
      .Add(New QueryParameter(OAuthVersionKey, OAuthVersion)) 
      .Add(New QueryParameter(OAuthNonceKey, nonce)) 
      .Add(New QueryParameter(OAuthTimestampKey, timeStamp)) 
      .Add(New QueryParameter(OAuthSignatureMethodKey, _SignatureTypeName)) 
      .Add(New QueryParameter(OAuthConsumerKeyKey, consumerKey)) 

      If Not (String.IsNullOrEmpty(token)) Then 
       .Add(New QueryParameter(OAuthTokenKey, token)) 
      End If 

      .Sort(New QueryParameterComparer) 
     End With 

     normalizedUrl = String.Format("{0}://{1}", url.Scheme, url.Host) 

     If Not ((url.Scheme = "http" AndAlso url.Port = 80) OrElse (url.Scheme = "https" AndAlso url.Port = 443)) Then 
      normalizedUrl = String.Format("{0}:{1}", normalizedUrl, url.Port) 
     End If 

     normalizedUrl = String.Format("{0}{1}", normalizedUrl, url.AbsolutePath) 

     normalizedRequestParameters = NormalizeRequestParameters(_params) 

     Dim _sb As New StringBuilder 
     With _sb 
      .AppendFormat(CultureInfo.InvariantCulture, "{0}&", httpMethod.ToUpper) 
      .AppendFormat(CultureInfo.InvariantCulture, "{0}&", UrlEncode(normalizedUrl)) 
      .AppendFormat(CultureInfo.InvariantCulture, "{0}", UrlEncode(normalizedRequestParameters)) 
     End With 

     Return _sb.ToString 

    End Function 
#End Region 

#Region "Private Methods" 
    Private Shared Function ComputeHash(ByVal hashAlgorithm As HashAlgorithm, ByVal data As String) As String 
     If hashAlgorithm Is Nothing Then 
      Throw New ArgumentNullException("hashAlgorithm") 
     End If 

     If String.IsNullOrEmpty(data) Then 
      Throw New ArgumentNullException("data") 
     End If 

     Dim _dataBuffer As Byte() = Encoding.ASCII.GetBytes(data) 
     Dim _hashBytes As Byte() = hashAlgorithm.ComputeHash(_dataBuffer) 

     Return Convert.ToBase64String(_hashBytes) 
    End Function 


    Private Shared Function NormalizeRequestParameters(ByVal parameters As IList(Of QueryParameter)) As String 

     Dim _p As QueryParameter 
     Dim _sb As New StringBuilder 

     For i As Integer = 0 To parameters.count - 1 
      _p = parameters(i) 
      _sb.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}", _p.Name, _p.Value) 

      If i < parameters.count - 1 Then 
       _sb.Append("&") 
      End If 
     Next 

     Return _sb.ToString 

    End Function 

    Private Shared Function GetQueryParameters(ByVal parameters As String) As List(Of QueryParameter) 
     If (parameters.StartsWith("?")) Then 
      parameters = parameters.Remove(0, 1) 
     End If 

     Dim _result As New List(Of QueryParameter) 
     Dim _p As String() = parameters.Split("&"c) 

     Dim _temp As String() 

     If Not (String.IsNullOrEmpty(parameters)) Then 

      For Each s As String In _p 
       If Not (String.IsNullOrEmpty(s)) AndAlso Not (s.StartsWith(OAuthParameterExclusionPrefix)) Then 'AndAlso (s.StartsWith(OAuthParameterPrefix)) Then 
        If s.IndexOf("=") > -1 Then 
         _temp = s.Split("="c) 
         _result.Add(New QueryParameter(_temp(0), _temp(1))) 
        Else 
         _result.Add(New QueryParameter(s, String.Empty)) 
        End If 
       End If 

      Next 

     End If 

     Return _result 

    End Function 
#End Region 


End Class 

然後一類使用這些較低級別的函數來構建和解析OAuth消息

Public MustInherit Class BaseOAuth 
    Inherits BaseAccess 

#Region "Class Declarations" 
    Protected Const CONSUMER_KEY As String = "anonymous" 
    Protected Const CONSUMER_SECRET As String = "anonymous" 

    Protected Const SCOPEURL As String = "http://gdata.youtube.com" ' 

    Protected m_FeedCollection As ArrayList 
#End Region 

#Region "Constructor" 
    Public Sub New() 
     MyBase.new() 
    End Sub 

    Public Sub New(ByVal context As Common.Statefulogic.Context) 
     MyBase.new(context) 
    End Sub 
#End Region 

#Region "Public Properties" 

#End Region 

#Region "Private Functions" 

#End Region 

#Region "Public Methods" 
    Public Function SignCommandUrl(ByVal commandUrl As String) As String 
     Return SignCommandUrl(commandUrl, Nothing, Nothing) 
    End Function 

    Public Function SignCommandUrl(ByVal commandUrl As String, ByVal overrideToken As String, ByVal overrideTokenSecret As String) As String 
     Dim _commandUri = New Uri(commandUrl) 
     Dim _oAuthSignature As String 
     Dim _oAuthTimeStamp As String = SharedOAuth.GenerateTimeStamp 
     Dim _oAuthNOnce As String = SharedOAuth.GenerateNonce 
     Dim _oAuth_normalized_url As String = String.Empty 
     Dim _oAuth_normalized_params As String = String.Empty 

     If Not (String.IsNullOrEmpty(overrideToken)) OrElse Not (String.IsNullOrEmpty(overrideTokenSecret)) Then 
      _oAuthSignature = SharedOAuth.GenerateSignature(_commandUri, CONSUMER_KEY, CONSUMER_SECRET, overrideToken, overrideTokenSecret, "GET", _oAuthTimeStamp, _oAuthNOnce, enumerations.OAuthEnumerations.SignatureTypes.HmacSha1, _oAuth_normalized_url, _oAuth_normalized_params) 
     Else 

      If MasterAccessToken Is Nothing Then 
       _oAuthSignature = SharedOAuth.GenerateSignature(_commandUri, CONSUMER_KEY, CONSUMER_SECRET, String.Empty, String.Empty, "GET", _oAuthTimeStamp, _oAuthNOnce, enumerations.OAuthEnumerations.SignatureTypes.HmacSha1, _oAuth_normalized_url, _oAuth_normalized_params) 
      Else 
       _oAuthSignature = SharedOAuth.GenerateSignature(_commandUri, CONSUMER_KEY, CONSUMER_SECRET, SharedOAuth.UrlEncode(MasterAccessToken.Token), MasterAccessToken.TokenSecret, "GET", _oAuthTimeStamp, _oAuthNOnce, enumerations.OAuthEnumerations.SignatureTypes.HmacSha1, _oAuth_normalized_url, _oAuth_normalized_params) 
      End If 
     End If 

     'Get a token 
     Dim _sb As New System.Text.StringBuilder 
     With _sb 
      .Append(_oAuth_normalized_url) 
      .Append("?") 
      .Append(_oAuth_normalized_params) 
      .Append("&") 
      .Append("oauth_signature") 
      .Append("=") 
      .Append(SharedOAuth.UrlEncode(_oAuthSignature)) 
     End With 

     Return _sb.ToString 
    End Function 

    Public Function BuildPostHeader(ByVal commandUrl As String) As String 
     Dim _commandUri = New Uri(commandUrl) 
     Dim _oAuthTimeStamp As String = SharedOAuth.GenerateTimeStamp 
     Dim _oAuthNOnce As String = SharedOAuth.GenerateNonce 
     Dim _oAuth_normalized_url As String = String.Empty 
     Dim _oAuth_normalized_params As String = String.Empty 
     Dim _oAuthSignature As String 

     If MasterAccessToken Is Nothing Then 
      _oAuthSignature = SharedOAuth.GenerateSignature(_commandUri, CONSUMER_KEY, CONSUMER_SECRET, String.Empty, String.Empty, "POST", _oAuthTimeStamp, _oAuthNOnce, enumerations.OAuthEnumerations.SignatureTypes.HmacSha1, _oAuth_normalized_url, _oAuth_normalized_params) 
     Else 
      _oAuthSignature = SharedOAuth.GenerateSignature(_commandUri, CONSUMER_KEY, CONSUMER_SECRET, SharedOAuth.UrlEncode(MasterAccessToken.Token), MasterAccessToken.TokenSecret, "POST", _oAuthTimeStamp, _oAuthNOnce, enumerations.OAuthEnumerations.SignatureTypes.HmacSha1, _oAuth_normalized_url, _oAuth_normalized_params) 
     End If 


     Dim _sb As New System.Text.StringBuilder 
     With _sb 
      .Append("Authorization: OAuth oauth_version=""1.0"", ") 
      .AppendFormat("oauth_nonce=""{0}"", ", _oAuthNOnce) 
      .AppendFormat("oauth_timestamp=""{0}"", ", _oAuthTimeStamp) 
      .AppendFormat("oauth_consumer_key=""{0}"", ", CONSUMER_KEY) 
      .AppendFormat("oauth_token=""{0}"", ", MasterAccessToken.Token) 
      .Append("oauth_signature_method=""HMAC-SHA1"", ") 
      .AppendFormat("oauth_signature=""{0}""", _oAuthSignature) 
     End With 

     Return _sb.ToString 
    End Function 

    Public Shared Function PostRequestReturnCollection(ByVal commandUrl As String) As NameValueCollection 
     Dim _nameValCollection As NameValueCollection 

     Dim _request As HttpWebRequest = CType(WebRequest.Create(commandUrl), HttpWebRequest) 

     Using _response As HttpWebResponse = CType(_request.GetResponse, HttpWebResponse) 
      Using _reader As TextReader = New StreamReader(_response.GetResponseStream) 
       _nameValCollection = HttpUtility.ParseQueryString(_reader.ReadToEnd) 
      End Using 
     End Using 

     Return _nameValCollection 
    End Function 
#End Region 

End Class 

最後一個調用來獲取OAuth憑證..

Public Function RequestApplicationAccess() As TokenParams 
    Dim _oAuthCallbackConfirmed As Boolean 
    Dim _oAuthTokenUrl As String 
    Dim _oauth_Authenticate_Page As String 
    Dim _oAuthtokendataCollection As NameValueCollection 
    Dim _request As HttpWebRequest 

    Dim _oauth_token As String = String.Empty 
    Dim _oauth_token_secret As String = String.Empty 
    Dim _oauth_verifier As String = String.Empty 

    m_CallbackSite = "http://www.previewthebestof.co.uk/_services/googleauth.aspx" 

    'Generate a signature 
    Dim _RequestUrl As String = "https://www.google.com/accounts/OAuthGetRequestToken" 
    _oAuthTokenUrl = SignCommandUrl(String.Format("{0}?scope={1}&oauth_callback={2}&xoauth_displayname={3}", _RequestUrl, SharedOAuth.UrlEncode(SCOPEURL), SharedOAuth.UrlEncode(m_CallbackSite), SharedOAuth.UrlEncode(APPDISPLAYNAME))) 

    _oAuthtokendataCollection = PostRequestReturnCollection(_oAuthTokenUrl) 

    _oauth_token = _oAuthtokendataCollection.Item("oauth_token") 
    _oauth_token_secret = _oAuthtokendataCollection.Item("oauth_token_secret") 

    If _oAuthtokendataCollection.Count = 3 Then 
     _oAuthCallbackConfirmed = CType(_oAuthtokendataCollection.Item("oauth_callback_confirmed"), Boolean) 
    End If 

    If String.IsNullOrEmpty(_oauth_token) OrElse String.IsNullOrEmpty(_oauth_token_secret) Then 
     Throw New N5.Common.ExceptionManager.N5Exception("Cannot get an authentication token (_oauth_token or _oauth_token_secret is blank)") 
    End If 

    '---------------------------------------------------- 
    'Write the token to the users profile 
    m_Context.UserObject.SetUserAuthenticationTokens(_oauth_token, String.Empty, String.Empty, String.Empty) 

    '----------------------------------------------------- 
    'Authorize the token 
    _RequestUrl = "https://www.google.com/accounts/OAuthAuthorizeToken" 

    _oAuthTokenUrl = String.Format("{0}?oauth_token={1}", _RequestUrl, SharedOAuth.UrlEncode(_oauth_token)) 

    _request = CType(WebRequest.Create(_oAuthTokenUrl), HttpWebRequest) 
    Using _response = CType(_request.GetResponse, HttpWebResponse) 
     Using _reader As TextReader = New StreamReader(_response.GetResponseStream) 
      _oauth_Authenticate_Page = _reader.ReadToEnd 
     End Using 
    End Using 

    If Not (_oauth_Authenticate_Page.ToLower.Contains("<html>")) Then 
     Throw New N5.Common.ExceptionManager.N5Exception("AuthToken Respose does not contain a webpage") 
    End If 

    'Response contains html, which is the youtube authentication page - need to show this to the user 
    'write to temp file 
    Dim _tempFileName As String = IO.Path.Combine(My.Computer.FileSystem.SpecialDirectories.Temp, String.Concat(FilenameUtilities.GetRandomFilename, ".htm")) 
    Using _tempFile As New StreamWriter(_tempFileName) 
     _tempFile.Write(_oauth_Authenticate_Page) 
    End Using 

    'Load a browser form and navigate to the file just created. 
    Using _browser As New BasePopupBrowser 
     With _browser 
      .WindowState = FormWindowState.Maximized 
      .AutoCloseText = "<H1>OAuth Token Authorised</H1>" 
      .CheckForAutoCloseText = True 
      .NavigateTo(New System.Uri(_tempFileName)) 
     End With 
    End Using 

    'Clean up the tempfile 
    My.Computer.FileSystem.DeleteFile(_tempFileName) 

    '------------------------------------------------------ 
    'Check the db for a request_token - did the user press authorise? 
    m_Context.UserObject.RefreshUserAuthenticationTokens() 
    Dim _dv As DataView = m_Context.UserObject.AuthenticationTokensDataView 
    _dv.RowFilter = "TokenName='YouTubeAuthVerifier'" 

    If _dv.Count > 0 Then 
     _oauth_verifier = _dv(0)("Value").ToString 
    End If 

    If String.IsNullOrEmpty(_oauth_verifier) Then 
     'We didnt get a verification token back, chances are the user pressed reject, Doh! 
     Return Nothing 
    End If 

    '--------------------------------------------------------- 
    'Now we need to exchange the request token for an access token 
    _RequestUrl = String.Format("https://www.google.com/accounts/OAuthGetAccessToken?oauth_verifier={0}", SharedOAuth.UrlEncode(_oauth_verifier)) 

    _oAuthTokenUrl = SignCommandUrl(_RequestUrl, _oauth_token, _oauth_token_secret) 

    _oAuthtokendataCollection = PostRequestReturnCollection(_oAuthTokenUrl) 

    _oauth_token = _oAuthtokendataCollection.Item("oauth_token") 
    _oauth_token_secret = _oAuthtokendataCollection.Item("oauth_token_secret") 

    m_Context.UserObject.SetUserAuthenticationTokens(String.Empty, String.Empty, _oauth_token, _oauth_token_secret) 

    Return New TokenParams(_oauth_token, _oauth_token_secret) 
End Function 
2

的Wrox的專業書Twitter的發展:隨着例子在.net 3.5具有從C#客戶端做的OAuth的演練,代碼可作爲從their website免費下載。

+0

這是我見過的最完整的例子。 +1 – shellscape

相關問題