.NET에서 확인 기능이있는 OAuth


103

OAuth 지원 응용 프로그램, 특히 Mendeley ( http : // dev )와 통합하기 위해 .NET 기반 클라이언트 앱 (WPF에서-당분간 콘솔 앱으로 수행하고 있음)을 만들려고합니다 . .mendeley.com ), 분명히 3-legged OAuth를 사용합니다.

OAuth를 처음 사용하고 시작하는 데 많은 어려움이 있습니다. .NET OAuth 라이브러리 또는 도우미를 여러 개 찾았지만 필요하다고 생각하는 것보다 더 복잡한 것 같습니다. 내가 원하는 것은 Mendeley API에 REST 요청을 발행하고 응답을받는 것입니다!

지금까지 시도했습니다.

첫 번째 (DotNetOpenAuth)는 방법을 알아 내려고 몇 시간과 시간을 투자하면 필요한 작업을 수행 할 수있는 것 같습니다. 내가 아는 한 두 번째와 세 번째는 Mendeley가 반송하는 인증 코드를 지원하지 않습니다.

저는 Mendeley에서 소비자 키와 비밀을 얻었으며 DotNetOpenAuth를 사용하여 사용자가 응용 프로그램에 입력 할 수있는 확인 코드를 제공하는 Mendeley 페이지와 함께 브라우저를 시작할 수있었습니다. 그러나이 시점에서 나는 길을 잃었고 그것을 애플리케이션에 현명하게 제공하는 방법을 찾을 수 없었다.

나는 이것으로 시작해야 할 곳을 모른다는 것을 매우 기꺼이 인정합니다 (비록 가파른 학습 곡선이있는 것처럼 보임에도 불구하고)-누군가가 나를 올바른 방향으로 가리킬 수 있다면 감사하겠습니다!

답변:


182

동의합니다. .NET 앱에 사용할 수있는 오픈 소스 OAuth 지원 클래스는 이해하기 어렵고 지나치게 복잡하며 (DotNetOpenAuth에 의해 노출되는 메서드 수는 몇 개입니까?) 잘못 설계되었습니다 (해당 Google의 OAuthBase.cs 모듈에서 문자열 매개 변수가 10 개인 메서드를 살펴보십시오. 제공 한 링크-상태 관리가 전혀 없음) 또는 그렇지 않으면 불만족 스럽습니다.

이렇게 복잡 할 필요는 없습니다.

저는 OAuth의 전문가는 아니지만 Twitter 및 TwitPic에서 성공적으로 사용하는 OAuth 클라이언트 측 관리자 클래스를 제작했습니다. 사용하기가 비교적 간단합니다. 오픈 소스이며 여기에서 사용할 수 있습니다 : Oauth.cs

검토를 위해 OAuth 1.0a에서 ... 좀 웃기지 만 특별한 이름이 있고 "표준"처럼 보이지만 "OAuth 1.0a"를 구현하는 유일한 서비스는 Twitter입니다. 충분히 표준이라고 생각합니다 . 어쨌든 OAuth 1.0a에서 데스크톱 앱에서 작동하는 방식 은 다음과 같습니다.

  1. 앱 개발자 인 귀하는 앱을 등록하고 "소비자 키"와 "소비자 비밀"을받습니다. Arstechnica에는 왜이 모델이 최고가 아닌지에 대한 잘 쓰여진 분석이 있지만 그들이 말했듯이 그것이 무엇인지입니다 .

  2. 앱이 실행됩니다. 처음 실행될 때 사용자가 앱에 대한 승인을 명시 적으로 부여하여 Twitter 및 그 자매 서비스 (예 : TwitPic)에 oauth 인증 REST 요청을 수행하도록해야합니다. 이렇게하려면 사용자의 명시적인 승인을 포함하는 승인 프로세스를 거쳐야합니다. 이것은 앱이 처음 실행될 때만 발생합니다. 이렇게 :

    • "요청 토큰"을 요청하십시오. 일명 임시 토큰.
    • 웹 페이지를 팝업하고 해당 요청 토큰을 쿼리 매개 변수로 전달합니다. 이 웹 페이지는 사용자에게 "이 앱에 대한 액세스 권한을 부여 하시겠습니까?"라고 묻는 UI를 표시합니다.
    • 사용자가 트위터 웹 페이지에 로그인하고 액세스를 허용하거나 거부합니다.
    • 응답 html 페이지가 나타납니다. 사용자가 액세스 권한을 부여한 경우 48pt 글꼴로 표시된 PIN이 있습니다.
    • 이제 사용자는 해당 핀을 잘라내어 Windows 양식 상자에 붙여넣고 "다음"또는 이와 유사한 것을 클릭해야합니다.
    • 그런 다음 데스크톱 앱은 "액세스 토큰"에 대한 oauth 인증 요청을 수행합니다. 또 다른 REST 요청.
    • 데스크톱 앱은 "액세스 토큰"과 "액세스 비밀"을받습니다.

승인이 끝나면 데스크톱 앱은 사용자를 대신하여 인증 된 요청을 수행하기 위해 사용자 별 "액세스 토큰"및 "액세스 비밀"(앱별 "소비자 키"및 "소비자 비밀"과 함께)을 사용할 수 있습니다. 트위터에. 사용자가 앱의 승인을 취소하거나 어떤 이유로 Twitter가 앱의 승인을 취소하거나 액세스 토큰 및 / 또는 비밀을 잃어버린 경우 승인 댄스를 다시 수행해야하지만 만료되지 않습니다. .


영리하지 않다면 UI 흐름은 다단계 OAuth 메시지 흐름을 미러링 할 수 있습니다. 더 나은 방법이 있습니다.

WebBrowser 컨트롤을 사용하고 데스크톱 앱에서 권한 부여 웹 페이지를 엽니 다. 사용자가 "허용"을 클릭하면 해당 WebBrowser 컨트롤에서 응답 텍스트를 가져 와서 PIN을 자동으로 추출한 다음 액세스 토큰을 가져옵니다. 5 개 또는 6 개의 HTTP 요청을 보내지 만 사용자는 단일 허용 / 거부 대화 상자 만 표시하면됩니다. 단순한.

이렇게 :
대체 텍스트


UI를 정렬 한 경우 남은 유일한 과제는 oauth 서명 된 요청을 생성하는 것입니다. 이것은 oauth 서명 요구 사항이 일종의 특별하기 때문에 많은 사람들을 괴롭 힙니다. 이것이 단순화 된 OAuth Manager 클래스가하는 일입니다.

토큰을 요청하는 예제 코드 :

var oauth = new OAuth.Manager();
// the URL to obtain a temporary "request token"
var rtUrl = "https://api.twitter.com/oauth/request_token";
oauth["consumer_key"] = MY_APP_SPECIFIC_KEY;
oauth["consumer_secret"] = MY_APP_SPECIFIC_SECRET;    
oauth.AcquireRequestToken(rtUrl, "POST");

그게 다야 . 단순한. 코드에서 볼 수 있듯이 oauth 매개 변수를 얻는 방법은 사전과 같은 문자열 기반 인덱서를 사용하는 것입니다. AcquireRequestToken 메서드는 요청 토큰 (일명 임시 토큰)을 부여하는 서비스의 URL로 oauth 서명 된 요청을 보냅니다. Twitter의 경우이 URL은 " https://api.twitter.com/oauth/request_token "입니다. oauth 사양은 oauth 매개 변수 세트 (token, token_secret, nonce, timestamp, consumer_key, version 및 callback)를 특정 방식 (URL 인코딩 및 앰퍼샌드로 결합) 및 사전 식으로 포장해야한다고 말합니다. 정렬 된 순서로, 그 결과에 서명을 생성 한 다음, 다른 방식으로 (쉼표로 결합) 새 oauth_signature 매개 변수에 저장된 서명과 함께 동일한 매개 변수를 압축합니다. OAuth 관리자 클래스가이 작업을 자동으로 수행합니다. 논 스와 타임 스탬프, 버전 및 서명을 자동으로 생성 합니다. 앱은 그 내용을 신경 쓰거나 인식 할 필요가 없습니다. oauth 매개 변수 값을 설정하고 간단한 메소드 호출을 수행하십시오. 관리자 클래스는 요청을 보내고 응답을 구문 분석합니다.

좋아, 그럼 뭐? 요청 토큰을 받으면 사용자가 명시 적으로 승인을 부여 할 웹 브라우저 UI를 표시합니다. 올바르게 수행하면 임베디드 브라우저에 표시됩니다. Twitter의 경우 URL은 " https://api.twitter.com/oauth/authorize?oauth_token= "이며 oauth_token이 추가됩니다. 다음과 같이 코드에서이 작업을 수행하십시오.

var url = SERVICE_SPECIFIC_AUTHORIZE_URL_STUB + oauth["token"];
webBrowser1.Url = new Uri(url);

(외부 브라우저에서이 작업을 수행했다면을 사용 System.Diagnostics.Process.Start(url)합니다.)

Url 속성을 설정하면 WebBrowser 컨트롤이 해당 페이지로 자동으로 이동합니다.

사용자가 "허용"버튼을 클릭하면 새 페이지가로드됩니다. HTML 양식이며 풀 브라우저에서와 동일하게 작동합니다. 코드에서 WebBrowser 컨트롤의 DocumentedCompleted 이벤트에 대한 처리기를 등록하고 해당 처리기에서 핀을 잡습니다.

var divMarker = "<div id=\"oauth_pin\">"; // the div for twitter's oauth pin
var index = webBrowser1.DocumentText.LastIndexOf(divMarker) + divMarker.Length;
var snip = web1.DocumentText.Substring(index);
var pin = RE.Regex.Replace(snip,"(?s)[^0-9]*([0-9]+).*", "$1").Trim();

그것은 약간의 HTML 화면 스크래핑입니다.

핀을 잡은 후에는 웹 브라우저가 더 이상 필요하지 않으므로 :

webBrowser1.Visible = false; // all done with the web UI

... Dispose ()를 호출 할 수도 있습니다.

다음 단계는 해당 핀과 함께 다른 HTTP 메시지를 전송하여 액세스 토큰을 가져 오는 것입니다. 이것은 위에서 설명한 oauth 순서 및 형식으로 구성된 또 다른 서명 된 oauth 호출입니다. 그러나 다시 한 번 OAuth.Manager 클래스를 사용하면 정말 간단합니다.

oauth.AcquireAccessToken(URL_ACCESS_TOKEN,
                         "POST",
                         pin);

Twitter의 경우 해당 URL은 " https://api.twitter.com/oauth/access_token "입니다.

이제 액세스 토큰이 있으며 서명 된 HTTP 요청에서 사용할 수 있습니다. 이렇게 :

var authzHeader = oauth.GenerateAuthzHeader(url, "POST");

... 여기는 url리소스 끝점입니다. 사용자의 상태를 업데이트하려면 " http://api.twitter.com/1/statuses/update.xml?status=Hello "가됩니다.

그런 다음 해당 문자열을 Authorization 이라는 HTTP 헤더에 설정합니다 .

TwitPic과 같은 타사 서비스와 상호 작용하려면 다음과 같이 약간 다른 OAuth 헤더 를 구성해야합니다 .

var authzHeader = oauth.GenerateCredsHeader(URL_VERIFY_CREDS,
                                            "GET",
                                            AUTHENTICATION_REALM);

Twitter의 경우 확인 자격 증명 url 및 영역의 값은 각각 " https://api.twitter.com/1/account/verify_credentials.json "및 " http://api.twitter.com/ "입니다.

... 넣어 는 HTTP 헤더라는에서 인증 문자열을 X-확인-자격 증명 승인 . 그런 다음 전송하는 요청과 함께 TwitPic과 같은 서비스로 보냅니다.

그게 다야.

모두 함께 트위터 상태를 업데이트하는 코드는 다음과 같을 수 있습니다.

// the URL to obtain a temporary "request token"
var rtUrl = "https://api.twitter.com/oauth/request_token";
var oauth = new OAuth.Manager();
// The consumer_{key,secret} are obtained via registration
oauth["consumer_key"] = "~~~CONSUMER_KEY~~~~";
oauth["consumer_secret"] = "~~~CONSUMER_SECRET~~~";
oauth.AcquireRequestToken(rtUrl, "POST");
var authzUrl = "https://api.twitter.com/oauth/authorize?oauth_token=" + oauth["token"];
// here, should use a WebBrowser control. 
System.Diagnostics.Process.Start(authzUrl);  // example only!
// instruct the user to type in the PIN from that browser window
var pin = "...";
var atUrl = "https://api.twitter.com/oauth/access_token";
oauth.AcquireAccessToken(atUrl, "POST", pin);

// now, update twitter status using that access token
var appUrl = "http://api.twitter.com/1/statuses/update.xml?status=Hello";
var authzHeader = oauth.GenerateAuthzHeader(appUrl, "POST");
var request = (HttpWebRequest)WebRequest.Create(appUrl);
request.Method = "POST";
request.PreAuthenticate = true;
request.AllowWriteStreamBuffering = true;
request.Headers.Add("Authorization", authzHeader);

using (var response = (HttpWebResponse)request.GetResponse())
{
    if (response.StatusCode != HttpStatusCode.OK)
        MessageBox.Show("There's been a problem trying to tweet:" +
                        Environment.NewLine +
                        response.StatusDescription);
}

OAuth 1.0a는 내부적으로는 복잡하지만 사용할 필요는 없습니다. OAuth.Manager는 나가는 oauth 요청의 생성과 응답에서 oauth 콘텐츠의 수신 및 처리를 처리합니다. Request_token 요청이 oauth_token을 제공하면 앱은이를 저장할 필요가 없습니다. Oauth.Manager는이를 자동으로 수행 할 수있을만큼 똑똑합니다. 마찬가지로 access_token 요청이 액세스 토큰과 시크릿을 되 찾을 때이를 명시 적으로 저장할 필요가 없습니다. OAuth.Manager가 해당 상태를 처리합니다.

후속 실행에서 이미 액세스 토큰과 시크릿이있는 경우 다음과 같이 OAuth.Manager를 인스턴스화 할 수 있습니다.

var oauth = new OAuth.Manager();
oauth["consumer_key"] = CONSUMER_KEY;
oauth["consumer_secret"] = CONSUMER_SECRET;
oauth["token"] = your_stored_access_token;
oauth["token_secret"] = your_stored_access_secret;

... 위와 같이 인증 헤더를 생성합니다.

// now, update twitter status using that access token
var appUrl = "http://api.twitter.com/1/statuses/update.xml?status=Hello";
var authzHeader = oauth.GenerateAuthzHeader(appUrl, "POST");
var request = (HttpWebRequest)WebRequest.Create(appUrl);
request.Method = "POST";
request.PreAuthenticate = true;
request.AllowWriteStreamBuffering = true;
request.Headers.Add("Authorization", authzHeader);

using (var response = (HttpWebResponse)request.GetResponse())
{
    if (response.StatusCode != HttpStatusCode.OK)
        MessageBox.Show("There's been a problem trying to tweet:" +
                        Environment.NewLine +
                        response.StatusDescription);
}

여기에서 OAuth.Manager 클래스가 포함 된 DLL을 다운로드 할 수 있습니다 . 해당 다운로드에는 도움말 파일도 있습니다. 또는 온라인으로 도움말 파일을 볼있습니다 .

여기 에서이 관리자를 사용하는 Windows Form의 예를 참조 하십시오 .


작업 예

여기에 설명 된 클래스와 기술을 사용하는 명령 줄 도구 의 작동 예제다운로드합니다 .


안녕하세요, 응답 해 주셔서 대단히 감사합니다! 나는 실제로 OAuth에서 이동했습니다 (나는 Mendeley를 포기하고 대안을 사용했습니다)-그러나 귀하의 답변을 읽었고 많은 의미가 있으며 매우 포괄적입니다. 나는 또한 내가 필요할지도 모르는 미래에 당신이 작성한 수업을 북마크했습니다! 다시 한번 감사드립니다.
John

2
안녕하세요 Cheeso 님, 코드와 자세한 설명을 공유해 주셔서 감사합니다. 훌륭하면서도 간단한 솔루션을 제공했습니다. 그러나 "oob"가 아닌 솔루션을 지원하려면 GetSignatureBase 메서드를 약간 변경해야합니다. "oob"가 아닌 경우 콜백을 URL 인코딩해야하므로 this._params를 반복 할 때 다음과 같이 추가해야합니다. if (p1.Key == "callback") {p.Add ( "oauth_"+ p1.Key, UrlEncode (p1.Value)); continue;}
Johnny

1
OAuth 2.0에서는 작동하지 않습니다. 이 클래스는 OAuth 1.0a 용입니다. OAuth2.0은 다양한 매개 변수의 서명 및 사전 정렬이 없기 때문에 사용이 훨씬 간단합니다. 따라서 OAuth 2.0을 수행하기 위해 외부 클래스가 필요하지 않을 것입니다. 또는 외부 클래스가 필요한 경우이 클래스보다 훨씬 간단 할 것입니다.
Cheeso 2015 년

1
도움말 파일 온라인으로 찾을 수 없습니다 cheeso.members.winisp.net/OAuthManager1.1
Kiquenet

3
모든 링크가 끊어진 것 같습니다. 여기에서 사본을 찾았습니다 : gist.github.com/DeskSupport/2951522#file-oauth-cs
John
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.