Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)
(시리즈 글이 7개 있습니다.)
.NET Framework: 193. 페이스북(Facebook) 계정으로 로그인하는 C# 웹 사이트 제작
; https://www.sysnet.pe.kr/2/0/953

.NET Framework: 198. 윈도우 응용 프로그램에 Facebook 로그인 연동
; https://www.sysnet.pe.kr/2/0/970

.NET Framework: 245. ASP.NET 서버 측 코드에서 페이스북 계정 연동하는 방법
; https://www.sysnet.pe.kr/2/0/1143

개발 환경 구성: 313. Nuget Facebook 라이브러리를 이용해 ASP.NET 웹 폼과 로그인 연동하는 방법
; https://www.sysnet.pe.kr/2/0/11182

개발 환경 구성: 436. 페이스북 HTTPS 인증을 localhost에서 테스트하는 방법
; https://www.sysnet.pe.kr/2/0/11855

개발 환경 구성: 482. Facebook OAuth 처리 시 상태 정보 전달 방법과 "유효한 OAuth 리디렉션 URI" 설정 규칙
; https://www.sysnet.pe.kr/2/0/12189

닷넷: 2201. C# - Facebook 연동 / 사용자 탈퇴 처리 방법
; https://www.sysnet.pe.kr/2/0/13526




ASP.NET 서버 측 코드에서 페이스북 계정 연동하는 방법

제 웹 사이트는 전에 설명드린 것처럼, 클라이언트 측의 "Login" 버튼을 통해서 자바 스크립트를 이용하여 로그인이 이루어지는 방식으로 페이스북과 연동이 됩니다.

페이스북(Facebook) 계정으로 로그인하는 C# 웹 사이트 제작
; https://www.sysnet.pe.kr/2/0/953

Facebook 연동 - API Error Description: Invalid OAuth 2.0 Access Token
; https://www.sysnet.pe.kr/2/0/959

그런데, (당연하겠지만 ^^) 서버 측에서 로그인 처리를 하는 방법도 있습니다. 이번엔 그 방법을 알아보고, 제 웹 사이트에서도 그렇게 적용해 보았습니다. ^^




그사이 제법 편한 라이브러리도 공개되어 있더군요.

Facebook Graph Toolkit - Latest Release: Version 2.0 beta
; http://fgt.codeplex.com/

ASP.NET Sample App
; http://www.facebook.com/apps/application.php?id=110010620072#!/apps/application.php?id=110010620072&sk=wall&filter=2

Site Integration Example
; http://computerbeacon.net/downloads/getfile.ashx?filename=fbsitetest_v2.zip

위의 "http://fgt.codeplex.com/" 웹 사이트를 통해서 "Facebook Graph Toolkit 2.1" 다운로드해 아래의 2가지 DLL을 제 웹 사이트에 참조 추가했습니다.

  • Facebook Graph Toolkit.dll
  • JSON.dll

이제 web.config을 열어서 "Facebook Graph Toolkit"과 "Facebook"을 연결하기 위한 설정을 해줍니다.

<configSections>
    <section name="FacebookGraphToolkitConfiguration" type="Facebook_Graph_Toolkit.FacebookGraphToolkitConfiguration"/>
</configSections>

<FacebookGraphToolkitConfiguration FacebookAppID="xxxxxxxxxxx" FacebookAppSecret="xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"/>

그다음, '세션' 설정을 추가해 주어야 합니다. 왜냐하면, "Facebook Graph Toolkit"에서 내부적으로 ASP.NET 세션을 사용하기 때문인데요. 음... 어쩔 수 없군요. ^^ 제 웹 사이트의 경우에 세션을 사용하지는 않았지만, 이것 때문에 활성화를 시켰습니다.

<system.web>
    ...[생략]...
    <sessionState mode="InProc"/>
    <pages enableSessionState="true" ...[생략]... />
</system.web>

자, 이제 소스 코드를 변경해 볼텐데요. 로그인 버튼을 포함한 aspx의 cs 파일을 열어서, SocialPage를 상속받도록 변경해 주어야 합니다.

using Facebook_Graph_Toolkit;

public class MyPage : SocialPage
{
...
}

그다음, 해당 페이지의 PreInit 이벤트에서 "ExtendedPermissions"를 설정합니다. 지난번 글에 보면, 제 홈페이지의 경우 fb:login 버튼에 이 값들을 설정해 두고 있었는데요.

<fb:login-button perms="email,user_website"></fb:login-button>

만약, 위와 같은 정보가 필요 없다면, 이 부분의 설정은 생략해도 됩니다. 하지만, 제 웹 사이트의 경우에는 필요했기 때문에 아래와 같이 OnPreInit 메서드를 재정의 해주었습니다.

protected override void OnPreInit(EventArgs e)
{
    base.OnPreInit(e);

    this.ExtendedPermissions = "email,user_website";
}

그다음, 로그인 버튼을 aspx 웹 페이지에 추가해 주고,

<asp:ImageButton ID="ImageButton1" runat="server" ImageUrl="/login-button.png" 
    onclick="ImageButton1_Click" />

로그인 버튼이 눌렸을 때의 서버 측 이벤트 핸들러에서 단순하게 SocialPage.RedirectToFacebookAuthorization 메서드를 호출해 주면 됩니다.

protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
{
    this.RedirectToFacebookAuthorization();
}

그럼, 내부적으로 "https://graph.facebook.com/oauth/authorize" 웹 페이지를 클라이언트 측 웹 브라우저가 방문하게 되고 로그인하게 됩니다. 정상적으로 로그인을 했으면 facebook 측에서는 다시 사용자가 원래 방문했던 웹 사이트로 redirection을 해줍니다.

그럼, Page의 부모 클래스였던 SocialPage의 OnLoad 메서드 내에서는, 재지정되어 전송된 URL로부터 "code" 쿼리 문자열 값을 알아내서 내부적으로 SocialPage.Api 클래스에 기본적인 Facebook 관련 정보들을 설정해 줍니다.

이때부터는, facebook으로부터 자유롭게 정보 조회를 할 수 있는데요. 예를 들어, 현재 로그인한 사용자 정보는 다음과 같이 구할 수 있습니다.

Facebook_Graph_Toolkit.GraphApi.User fbUser = new User("me", Api.AccessToken);

string userName = fbUser.Name;
string email = fbUser.Email;
string uid = fbUser.ID;




그런데, 2가지 문제가 있더군요. 첫 번째는, fbUser에서 제공되는 정보에는 확장 속성으로 요청한 "user_website" 값이 없다는 점입니다. 이를 해결하려면 페이스북에서 배포되는 Graph API를 그대로 사용하면 됩니다. 어차피 AccessToken 값만 있으면 되기 때문에 다음과 같이 구해올 수 있습니다.

Facebook.FacebookAPI api = new Facebook.FacebookAPI(Api.AccessToken);
Facebook.JSONObject me = null;
me = api.Get("/me");

if (me.Dictionary.ContainsKey("website") == true)
{
    Facebook.JSONObject value = me.Dictionary["website"];
    if (value != null)
    {
        string user_website = value.String;
    }
}

또 한 가지는, 이건 아마도 페이스북의 문제인 것 같습니다.

예를 들어, 사용자가 방문한 웹 사이트가 "http://test.com"라고 할 때, 이런 URL로 방문한 상태에서는 정상적으로 페이스북 로그인이 이뤄지지만, 쿼리 문자열을 하나라도 포함하고 있으면 예외가 발생했습니다. 즉, "http://test.com/test.aspx?myValue=0"과 같이 myValue라는 쿼리 문자열을 포함하면 "Facebook Graph Toolkit"을 사용하면 예외가 발생하고 이벤트 로그에 다음과 같은 기록을 볼 수 있습니다.

Log Name:      Application
Source:        ASP.NET 4.0.30319.0
Date:          2011-10-09 오후 10:10:28
Event ID:      1309
Task Category: Web Event
Level:         Warning
Keywords:      Classic
User:          N/A
Computer:      Web2008.testpc.co.kr
Description:
Event code: 3005 
Event message: An unhandled exception has occurred. 
Event time: 2011-10-09 오후 10:10:28 
Event time (UTC): 2011-10-09 오후 1:10:28 
Event ID: 478a718c878c40dea2b712c611343e81 
Event sequence: 36 
Event occurrence: 3 
Event detail code: 0 
 
Application information: 
    Application domain: /LM/W3SVC/1/ROOT-39-129632393463486808 
    Trust level: Full 
    Application Virtual Path: / 
    Application Path: C:\inetpub\wwwroot\ 
    Machine name: Web2008 
 
Process information: 
    Process ID: 3108 
    Process name: w3wp.exe 
    Account name: NT AUTHORITY\SYSTEM 
 
Exception information: 
    Exception type: FacebookException 
    Exception message: OAuthException : Error validating verification code.
   at Facebook_Graph_Toolkit.Helpers.WebResponseHelper.GetWebResponseObject(String url)
   at Facebook_Graph_Toolkit.Helpers.WebResponseHelper.GetWebResponse(String url)
   at Facebook_Graph_Toolkit.SocialPage.OnLoad(EventArgs e)
   at System.Web.UI.Control.LoadRecursive()
   at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
 
Request information: 
    Request URL: http://test.com/test.aspx?myValue=0&code=...[생략]... 
    Request path: /Default.aspx 
    User host address: 192.168.50.2
    User:  
    Is authenticated: False 
    Authentication Type:  
    Thread account name: NT AUTHORITY\SYSTEM 
 
Thread information: 
    Thread ID: 25 
    Thread account name: NT AUTHORITY\SYSTEM 
    Is impersonating: False 
    Stack trace:    at Facebook_Graph_Toolkit.Helpers.WebResponseHelper.GetWebResponseObject(String url)
   at Facebook_Graph_Toolkit.Helpers.WebResponseHelper.GetWebResponse(String url)
   at Facebook_Graph_Toolkit.SocialPage.OnLoad(EventArgs e)
   at System.Web.UI.Control.LoadRecursive()
   at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

문제의 원인을 파악하기 위해서는 SocialPage.RedirectToFacebookAuthorization 메서드 내부를 들여다 보아야 합니다.

protected void RedirectToFacebookAuthorization()
{
    this.FacebookAppConfigManager.Initialize();
    string url = string.Format("https://graph.facebook.com/oauth/authorize?client_id={0}&redirect_uri={1}&scope={2}", this.FacebookAppConfigManager.FacebookAppID, base.Request.Url.AbsoluteUri, this.ExtendedPermissions);
    base.Response.Redirect(url, true);
}

보시면, redirect_uri에 "base.Request.Url.AbsoluteUri" 값을 사용하는데, 결국 "http://test.com/test.aspx?myValue=0" 값이 들어가는 것을 볼 수 있는데요. "Facebook Graph Toolkit"을 사용하지 않고 직접 페이스북에 쿼리 문자열을 포함한 체로 방문을 해봐도 오류가 발생합니다. (쿼리 문자열 부분을 제외하면 로그인이 성공합니다.) 비록, 페이스북 자체에서 쿼리 문자열을 받아들이는 것에 오류가 있다는 것이지만 사용자 웹 사이트에서는 redirect_uri 값으로 넘어가는 URL에 쿼리 문자열이 들어가지 않도록 주의를 해줘야 합니다.

만약, 부득이하게 쿼리 문자열이 포함되어 있는 웹 페이지에서 로그인 시도가 발생한다면? 어쩔 수 없습니다. "Facebook Graph Toolkit"의 소스 코드를 변경해 주는 것이 좋습니다. (소스 코드는 "http://fgt.codeplex.com/" 내에서 다운로드 할 수 있습니다.)

가능한 변경을 최소화하기 위해, 제 경우에는 "this.FacebookAppConfigManager.Initialize();"의 Initialize 메서드를 internal에서 public으로 바꿔주고 다시 소스 코드를 빌드했습니다. 그런 다음, 직접 SocialPage를 상속받은 웹 페이지에서 "RedirectToFacebookAuthorization" 역할을 하는 별도의 메서드를 다음과 같이 구현해 주었습니다.

public void RedirectToFacebook()
{
    string thisUrl = Request.Url.GetLeftPart(UriPartial.Path);

    this.FacebookAppConfigManager.Initialize();

    string url = string.Format("https://graph.facebook.com/oauth/authorize?client_id={0}&redirect_uri={1}&scope={2}",
        this.FacebookAppConfigManager.FacebookAppID, thisUrl, this.ExtendedPermissions);

    base.Response.Redirect(url, true);
}





[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 7/5/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... [16]  17  18  19  20  21  22  23  24  25  26  27  28  29  30  ...
NoWriterDateCnt.TitleFile(s)
13232정성태1/27/20234860스크립트: 43. uwsgi의 --processes와 --threads 옵션
13231정성태1/27/20233786오류 유형: 839. python - TypeError: '...' object is not callable
13230정성태1/26/20234143개발 환경 구성: 660. WSL 2 내부로부터 호스트 측의 네트워크로 UDP 데이터가 1개의 패킷으로만 제한되는 문제
13229정성태1/25/20235159.NET Framework: 2090. C# - UDP Datagram의 최대 크기
13228정성태1/24/20235258.NET Framework: 2089. C# - WMI 논리 디스크가 속한 물리 디스크의 정보를 얻는 방법 [2]파일 다운로드1
13227정성태1/23/20234953개발 환경 구성: 659. Windows - IP MTU 값을 바꿀 수 있을까요? [1]
13226정성태1/23/20234676.NET Framework: 2088. .NET 5부터 지원하는 GetRawSocketOption 사용 시 주의할 점
13225정성태1/21/20233904개발 환경 구성: 658. Windows에서 실행 중인 소켓 서버를 다른 PC 또는 WSL에서 접속할 수 없는 경우
13224정성태1/21/20234265Windows: 221. Windows - Private/Public/Domain이 아닌 네트워크 어댑터 단위로 방화벽을 on/off하는 방법
13223정성태1/20/20234473오류 유형: 838. RDP 연결 오류 - The two computers couldn't connect in the amount of time allotted
13222정성태1/20/20234146개발 환경 구성: 657. WSL - DockerDesktop.vhdx 파일 위치를 옮기는 방법
13221정성태1/19/20234375Linux: 57. C# - 리눅스 프로세스 메모리 정보파일 다운로드1
13220정성태1/19/20234471오류 유형: 837. NETSDK1045 The current .NET SDK does not support targeting .NET ...
13219정성태1/18/20234020Windows: 220. 네트워크의 인터넷 접속 가능 여부에 대한 판단 기준
13218정성태1/17/20233952VS.NET IDE: 178. Visual Studio 17.5 (Preview 2) - 포트 터널링을 이용한 웹 응용 프로그램의 외부 접근 허용
13217정성태1/13/20234538디버깅 기술: 185. windbg - 64비트 운영체제에서 작업 관리자로 뜬 32비트 프로세스의 덤프를 sos로 디버깅하는 방법
13216정성태1/12/20234792디버깅 기술: 184. windbg - 32비트 프로세스의 메모리 덤프인 경우 !peb 명령어로 나타나지 않는 환경 변수
13215정성태1/11/20236374Linux: 56. 리눅스 - /proc/pid/stat 정보를 이용해 프로세스의 CPU 사용량 구하는 방법 [1]
13214정성태1/10/20235915.NET Framework: 2087. .NET 6부터 SourceGenerator와 통합된 System.Text.Json [1]파일 다운로드1
13213정성태1/9/20235443오류 유형: 836. docker 이미지 빌드 시 "RUN apt install ..." 명령어가 실패하는 이유
13212정성태1/8/20235200기타: 85. 단정도/배정도 부동 소수점의 정밀도(Precision)에 따른 형변환 손실
13211정성태1/6/20235229웹: 42. (https가 아닌) http 다운로드를 막는 웹 브라우저
13210정성태1/5/20234317Windows: 219. 윈도우 x64의 경우 0x00000000`7ffe0000 아래의 주소는 왜 사용하지 않을까요?
13209정성태1/4/20234234Windows: 218. 왜 윈도우에서 가상 메모리 공간은 64KB 정렬이 된 걸까요?
13208정성태1/3/20234203.NET Framework: 2086. C# - Windows 운영체제의 2MB Large 페이지 크기 할당 방법파일 다운로드1
13207정성태12/26/20224462.NET Framework: 2085. C# - gpedit.msc의 "User Rights Assignment" 특권을 코드로 설정/해제하는 방법파일 다운로드1
... [16]  17  18  19  20  21  22  23  24  25  26  27  28  29  30  ...