【问题标题】:How do you use openAuth from a windows client application?如何从 Windows 客户端应用程序使用 openAuth?
【发布时间】:2010-10-05 09:35:23
【问题描述】:

我正在考虑将公共 API 集成到现有的 Windows 窗体应用程序中。该 api 需要 openAuth 身份验证。我看到的所有这方面的例子都是基于 Web 的应用程序。

如何在客户端应用程序上使用 openAUth?

谢谢

【问题讨论】:

    标签: c# winforms oauth


    【解决方案1】:

    这不是最容易解释的事情,但我这样做是为了实现 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 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~"
    
        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 的《Professional Twitter Development: With Examples in .NET 3.5》一书介绍了从 C# 客户端执行 OAuth,代码可从their website 免费下载。

      【讨论】:

      • 这是我见过的最完整的例子。 +1
      猜你喜欢
      • 2016-01-01
      • 2019-05-11
      • 2018-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多