성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] How can I tell whether two programs...
[정성태] The case of the fail-fast crashes c...
[정성태] Creating Docker multi-arch images f...
[정성태] BinaryFormatter removed from .NET 9...
[정성태] Extending the Windows Shell Progres...
[우광현] 와..... 범위를 잡았으니 클라이언트가 해당 범위를 확인해본다...
[정성태] 딱히, 그것 이상으로 더 설명할 내용이 없습니다. 동적 포...
[정성태] If Windows 3.11 required a 32-bit p...
[정성태] What is a hard error, and what make...
[괴물신인] 질문작성자인데 이 글을 이제봤네요 ㄷㄷ 이 글처럼 타입별로 인...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <div style='font-family: 맑은 고딕, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>트위터 계정으로 로그인하는 C# 웹 사이트 제작</div> <br /> 사이트 만들 때 마다 사용자 로그인을 위한 DB를 유지해야 하는데요. 때로는, 그냥 유명 사이트의 계정과 연동하는 것이 여러 모로 이득이 되는 경우가 있습니다. 이번 글에서는, 우리가 흔히 알고 있는 사이트 중에서 "트위터(Twitter.com)"의 계정으로 인증 받을 수 있는 ASP.NET 웹 사이트를 제작해 보겠습니다.<br /> <br /> 이를 위해서 .NET에서 트위터 API 연동을 쉽게 해주는 라이브러리를 사용할 텐데요. 저는 Twitterizer를 선택했습니다. 다음의 웹 사이트에서 다운로드 받을 수 있고, 간단하게 Twitterizer2.dll을 참조하기만 하면 끝입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > Twitterizer - A .NET library for Twitter folk ; <a target='_tab' href='http://www.twitterizer.net/'>http://www.twitterizer.net/</a> Full - download ; <a target='_tab' href='http://www.twitterizer.net/files/Twitterizer2-2.3.zip'>http://www.twitterizer.net/files/Twitterizer2-2.3.zip</a> </pre> <br /> 본격적인 구현에 앞서, 여러분들의 웹 사이트에서 트위터 연동 기능을 제공하려면 반드시 트위터 사이트에서 해당 (웹) 응용 프로그램을 등록시켜 주어야 합니다. 이에 대해서는 다음의 사이트에서 잘 설명해 주고 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > 트위터 twitter API 어플리케이션 등록하기 ; <a target='_tab' href='http://smok95.tistory.com/213'>http://smok95.tistory.com/213</a> </pre> <br /> 위의 글에서는 "Application Type"을 "Client"로 설정했는데, 이번 글의 예제를 위해서는 "Browser"로 바꿨으나 그다지 큰 의미는 없어 보입니다. <br /> <br /> 등록과정을 거치면 ConsumerKey와 CustomerSecret를 할당받게 되는데, 여기까지 완료하셨으면 "개발 준비" 단계까지는 완료되었다고 볼 수 있습니다. ^^<br /> <br /> <hr style='width: 50%' /><br /> <br /> 자,,, 그럼 한번 트위터 계정 로그인에 묻어가는 코드를 작성해 볼까요?<br /> <br /> 우선, "로그인" 버튼을 만들어야겠지요. ^^ default.aspx에 로그인 버튼을 하나 만들고 그에 대해 서버 측 Click 이벤트 핸들러를 등록합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > ==== default.aspx ==== <asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" /> ==== default.aspx.cs ==== protected void Button1_Click(object sender, EventArgs e) { string consumerKey = ConfigurationManager.AppSettings["ConsumerKey"]; string consumerSecret = ConfigurationManager.AppSettings["ConsumerSecret"]; OAuthTokenResponse otr = <b style='COLOR: blue'>OAuthUtility.GetRequestToken</b>(consumerKey, consumerSecret, "http://127.0.0.1:48236/oauth_twitter.aspx"); Uri uri = <b style='COLOR: blue'>OAuthUtility.BuildAuthorizationUri</b>(otr.Token); <b style='COLOR: blue'>Response.Redirect(uri.AbsoluteUri);</b> } </pre> <br /> 소스 코드를 찬찬히 들여다 보면, 일단, consumerKey, consumerSecret 문자열은 트위터에 응용 프로그램 등록하면서 받았던 문자열입니다. 위의 코드에서는 appSettings에 넣어두었던 것을 그대로 재사용한 것이고.<br /> <br /> 다음으로, RequestToken 값을 OAuthUtility.GetRequestToken 메서드를 이용해서 받아올 수 있습니다. 트위터 계정과 연동하는 것이기 때문에 반드시 트위터 웹 사이트에서 "사용자가 직접 로그인"하는 과정을 거치게 됩니다. 이를 위해서 트위터로 사용자 방문을 시켜야하는데, 트위터 측의 로그인 URL을 얻기 위해서 OAuthUtility.BuildAuthorizationUri 메서드를 호출하여 줍니다. 그런 다음, Response.Redirect시키면 사용자의 웹 브라우저는 트위터의 로그인 화면을 보여줍니다.<br /> <br /> 이제 사용자는 로그인을 하게 되고, ("Remember me" 옵션을 이전에 체크하고 로그인을 했다거나, 같은 브라우저 세션에서 이미 로그인을 했었다면 로그인 과정은 생략됨) 아래와 같이 사용자로 하여금 "consumerKey"에 해당하는 그 응용 프로그램을 신뢰할 것인지를 묻게 됩니다.<br /> <br /> [그림 1: 응용 프로그램 측에 사용자 데이터 접근 허용]<br /> <img onclick='toggle_img(this)' class='imgView' alt='integrate_twitter_account_1.png' src='/SysWebRes/bbs/integrate_twitter_account_1.png' /><br /> <br /> 이 과정에서 사용자가 "Allow" 버튼을 누르면 트위터 측에서는 이전에 OAuthUtility.GetRequestToken의 3번째 인자로 넘겨 주었던 "<a target='_tab' href='http://127.0.0.1'>http://127.0.0.1</a>:48236/oauth_twitter.aspx" 콜백 URL로 사용자 웹 브라우저를 이동시킵니다. 이 때, 인증받은 정보를 Query String 형식으로 다음과 같이 넘겨주게 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > oauth_twitter.aspx?<b style='COLOR: blue'>oauth_token</b>=...[Access 토큰값]&<b style='COLOR: blue'>oauth_verifier</b>=[PIN 정보] </pre> <br /> 특이하죠. 이 때문에, 사용자는 트위터 이외에 자신이 이용하려는 다른 웹 사이트가 계정 정보를 소유하지 못하도록 하는 효과를 갖습니다. 즉, 위의 "SysnetTestWebApp" 웹 사이트는 사용자의 트위터 ID/PW를 알 수 없고 인증되었다는 그 사실만을 알게 되는 것입니다.<br /> <br /> "SysnetTestWebApp" 웹 사이트 측에서는, 사용자에 대한 정보나 사용자를 대신해서 트위터 서비스를 이용하려면 위의 콜백 URL에서 전달받았던 oauth_token, oauth_verifier 값을 이용해서 다음과 같이 Access 토큰 값을 얻을 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > ==== oauth_twitter.aspx ==== public partial class oauth_twitter : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { string requestToken = Request.QueryString["oauth_token"]; string accessVerifier = Request.QueryString["oauth_verifier"]; string consumerKey = ConfigurationManager.AppSettings["ConsumerKey"]; string consumerSecret = ConfigurationManager.AppSettings["ConsumerSecret"]; OAuthTokenResponse accessTokenResponse = <b style='COLOR: blue'>OAuthUtility.GetAccessToken</b>(consumerKey, consumerSecret, requestToken, accessVerifier); string accessToken = accessTokenResponse.Token; string accessTokenSecret = accessTokenResponse.TokenSecret; TextBox1.Text = <b style='COLOR: blue'>accessTokenResponse.UserId</b>.ToString(); TextBox2.Text = <b style='COLOR: blue'>accessTokenResponse.ScreenName</b>; } } ==== 실행 결과 ==== 사용자 ID: xxxxxxxx 사용자 이름: techsharer </pre> <br /> 그럼, 설명이 모두 끝난 것 같군요. 위에서 중요한 것은 accessToken, accessTokenSecret 값입니다. 만약, 다음 번에 "SysnetTestWebApp" 웹 사이트를 방문했을 때 로그인 과정을 생략하도록 "Remember Me"와 같은 기능을 제공하고 싶다면 "accessToken, accessTokenSecret" 2가지 값을 DB에 저장해 둔 후, 그 값을 조회할 수 있는 키를 사용자 측에 쿠키값으로 내려주는 방식으로 구현할 수 있습니다.<br /> <br /> 또, 어떻게 응용할 수 있을까요? 위의 웹 사이트는 전적으로 모든 인증 관리를 트위터에 맡겼지만, 이와 달리 자체 로그인 정보를 유지하는 웹 사이트가 그 사용자의 트위터 연동을 하고 싶은 경우도 있을 텐데요. 이런 경우에는 해당 사용자의 로그인 정보 테이블에 "accessToken, accessTokenSecret" 값을 모두 보관하고 있다가 트위터 연동 API를 호출해야 할 필요가 있을 때 액세스 토큰을 재 구성해서 트위터 API를 이용하는 것도 가능합니다.<br /> <br /> 실제로, 대부분의 트위터 연동 API는 "accessToken, accessTokenSecret" 값을 기반으로 하는 인증 토큰을 요구합니다. 예를 들어, 위에서처럼 로그인한 사용자의 Timeline 목록을 원한다면 다음과 같이 코딩하는 것이 가능합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > <b style='COLOR: blue'>OAuthTokens authToken = new OAuthTokens();</b> authToken.AccessToken = <b style='COLOR: blue'>accessToken</b>; authToken.AccessTokenSecret = <b style='COLOR: blue'>accessTokenSecret</b>; authToken.ConsumerKey = consumerKey; authToken.ConsumerSecret = consumerSecret; TimelineOptions to = new TimelineOptions(); to.Count = 20; to.IncludeRetweets = false; TwitterResponse<TwitterStatusCollection> tr = <b style='COLOR: blue'>TwitterTimeline.HomeTimeline(authToken, to)</b>; TwitterStatusCollection tsc = tr.ResponseObject; StringBuilder sb = new StringBuilder(); for (int i = 0; i < tsc.Count; i++) { TwitterStatus ts = tsc[i]; sb.AppendLine(ts.CreatedDate.ToString() + " : " + ts.Text + " from " + ts.User.ScreenName); } </pre> <br /> 이렇게 해서 트위터 계정 연동을 알아봤는데요. 개인적으로 아쉬웠던 점이 2가지 정도 있었습니다. (둘다 제가 방법을 모른 걸 수도 있습니다. ^^)<br /> <br /> 첫 번째는, 원래의 트위터 웹 사이트와 SSO(Single-sign on)가 되도록 하고 싶었는데, 이것이 가능하지 않는 것 같아서 구현을 하지 못했습니다. 즉, 사용자가 트위터 웹 사이트를 보다가 "SysnetTestWebApp" 웹 사이트로 이동을 하면 자연스럽게 로그인 상태로 나오면 좋겠는데,,, 안된다는 것!<br /> <br /> 두 번째는, 사용자가 트위터 웹 사이트로 이동한 후 로그인을 정상적으로 한 다음, 매번 "[그림 1]"과 같이 "허락"을 구하는 화면이 나온다는 것입니다. 좀 귀찮을 수도 있는 단계인데요. 아마도 이를 우회하기위해서라도 연동 웹 사이트 측에서는 "Remember Me"와 같은 기능을 구현해 두는 것이 좋을 것 같습니다.<br /> <br /> 음... 어쨌든, 테스트해 보고 나니 마음에 듭니다. 이참에 "<a target='_tab' href='http://www.sysnet.pe.kr'>SYSNET</a>" 웹 사이트를 아예 트위터 계정 연동으로 돌려버릴까... 고민이 좀 되는군요. ^^<br /> <br /> <a target='_tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=558&boardid=331301885'>첨부한 소스는 지금까지의 코드</a>를 포함하고 있으니 참고하시면 되겠습니다. ^^ (물론, consumerKey 등의 정보는 제거되었으니, 각자가 받은 키를 web.config의 appSettings에 넣어주시면 잘 동작할 것입니다.)<br /> <br /> <hr style='width: 50%' /><br /> <br /> 마지막으로, 참고할 만한 XAuth 인증 방법!<br /> <br /> 처음, Twitterizer2를 이용하여 프로그램을 하려고 했을 때는 Twitter API에 대해 잘 감싼 형태로 되어 있을 거라 판단하고 인증 과정을 단순하게 봤습니다. 실제로 Twitterizer에는 다음과 같이 ConsumerKey와 CustomerSecret 정보와 함께 트위터 계정 정보만으로 인증하는 API가 제공되고 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > string consumerKey = ConfigurationManager.AppSettings["ConsumerKey"]; string consumerSecret = ConfigurationManager.AppSettings["ConsumerSecret"]; OAuthTokenResponse otr = <b style='COLOR: blue'>XAuthUtility.GetAccessTokens</b>(consumerKey, consumerSecret, "[트위터 ID]", "[트위터 비밀번호"); </pre> <br /> 하지만, 정작 실행을 하면 다음과 같이 예외가 발생합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > Twitterizer.TwitterizerException was unhandled by user code Message=<b style='COLOR: blue'>The remote server returned an error: (401) Unauthorized.</b> <?xml version="1.0" encoding="UTF-8"?> <hash> <error>Client application is not permitted to use xAuth.</error> <request>/oauth/access_token?x_auth_username=[계정ID]&x_auth_password=[계정암호]&x_auth_mode=client_auth</request> </hash> </pre> <br /> 왜 오류가 발생하는지는 다음의 블로그에서 설명이 되어 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > Twitter Client/Browser 개발을 위한 인증(oAuth, xAuth) ; <a target='_tab' href='http://dreamofblue.tistory.com/73'>http://dreamofblue.tistory.com/73</a> </pre> <br /> 그리고, 전체적인 OAuth 인증 과정 이해는 다음의 글을 참조하시면 도움이 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > 트위터 twitter API - liboauth를 이용한 OAuth인증 및 API사용 예 ; <a target='_tab' href='http://smok95.tistory.com/214'>http://smok95.tistory.com/214</a> </pre> <br /> 앞으로의 웹 세계를 생각한다면, OAuth나 Windows Identity Management와 같은 식의 인증 처리에 익숙해지는 것이 필수가 아닐까 싶군요. ^^<br /> <br /> <hr style='width: 50%' /><br /> <br /> [파이썬의 경우]<br /> <br /> Twitter 검색을 위한 개발자 플랫폼에 로그인하고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Twitter Developer Platform ; <a target='tab' href='https://developer.twitter.com/'>https://developer.twitter.com/</a> </pre> <br /> App 생성과 함께 보이는 4개의 키 값을 복사한 후,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > api_key = 'Fy...[생략]...HA' api_secret = '4p...[생략]...vE' access_token = '17...[생략]...1c' access_token_secret = 'mV...[생략]...OK' </pre> <br /> 다음과 같이 tweepy 모듈로 간단하게 코딩!<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > import tweepy auth = tweepy.OAuthHandler(api_key, api_secret) auth.set_access_token(access_token, access_token_secret) api = tweepy.API(auth) keyword = '.NET5' search = [] tweets = api.search(q=keyword, count=100) for tweet in tweets: search.append(tweet) data = {} i = 1 print('[' + keyword + '에 대한 트윗 글') for tweet in search: data['text'] = tweet.text print(i, ':', data) i += 1 </pre> <br /> <hr style='width: 50%' /><br /> <br /> 연관은 없지만, 마찬가지로 SNS 검색이라는 관점에서 "NAVER 블로그 검색"도 해볼까요? ^^ 우선 개발자 플랫폼에,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Documents > 서비스 API > 검색 ; <a target='tab' href='https://developers.naver.com/docs/serviceapi/search/blog/blog.md#%EB%B8%94%EB%A1%9C%EA%B7%B8'>https://developers.naver.com/docs/serviceapi/search/blog/blog.md#%EB%B8%94%EB%A1%9C%EA%B7%B8</a> </pre> <br /> Open API 이용 신청을 하고, App 생성 시 발급받는 client_key와 client_secret을 복사 후,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > client_key = 'Uu...[생략]...gc' client_secret = 'lc...[생략]...1w' </pre> <br /> 이렇게 간단하게 코딩 완료!<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > import urllib.parse from urllib import request, parse import json query = '.NET5' encText = urllib.parse.quote(query) blog_search_url = 'https://openapi.naver.com/v1/search/blog?query=' + encText + '&display=100' req = request.Request(blog_search_url) req.add_header("X-Naver-Client-Id", client_key) req.add_header("X-Naver-Client-Secret", client_secret) resp = request.urlopen(req) resp_code = resp.getcode() if resp_code == 200: response_body = resp.read() dataList = json.loads(response_body) for data in dataList['items']: print(data['title']) print('[' + data['description'] + ']') else: print('오류코드: ' + resp_code) </pre> <br /> <br /><br /><hr /><span style='color: Maroon'>[이 토픽에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1726
(왼쪽의 숫자를 입력해야 합니다.)