Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 4개 있습니다.)
(시리즈 글이 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




페이스북(Facebook) 계정으로 로그인하는 C# 웹 사이트 제작

트위터 계정 연동을 알아보았는데요.

트위터 계정으로 로그인하는 C# 웹 사이트 제작
; https://www.sysnet.pe.kr/2/0/948

기왕 하는 거 ^^ 페이스북도 알아봐야 하지 않을까요?
어차피 모두 OAuth 인증 방식을 도입했기 때문에 접근 방법도 비슷해서 부담이 적습니다.




지난 번처럼, 우선 .NET 용 라이브러리를 찾아야 할텐데요. 오픈 소스로 되어 있는 다음의 라이브러리가 Facebook에 의해서 링크되어 있습니다.

C# SDK for Facebook Platform 
; https://github.com/facebook/csharp-sdk

소스 코드로만 공개되어 있기 때문에 번거롭지만 다운로드 받아서 빌드를 직접 해줘야 합니다. (FacebookAPI.dll)

그다음, 트위터와 마찬가지로 페이스북 역시 여러분들의 응용 프로그램을 등록해 줘야 합니다. 검색을 해보니, 아래의 사이트에서 잘 설명을 해주고 있습니다. ^^

SNS - 페이스북에 어플리케이션 올리기
; http://sherlockpj.blog.me/70091818802

위에서 일러준데로, http://www.facebook.com/developers 링크로 이동해서 로그인을 하고, 아래의 허가 요청에 대해서 허용을 합니다. (특이하게도, 페이스북 내부의 개발자 설정 역시도 페이스북의 '외부 응용 프로그램'처럼 대우를 하는군요.)

integrate_facebook_auth_1.png

다음으로, "새 어플리케이션 설정" 버튼을 누르고,

integrate_facebook_auth_2.png

응용 프로그램 이름을 입력하고, 생성!

integrate_facebook_auth_3.png

이후의 과정은 각자 응용 프로그램 상황에 맞게 설정하고 확인을 누르면 완료.




트위터의 경우에 "Consumer Key"와 "CustomerSecret"를 얻을 수 있었던 것처럼, 페이스북에서도 비슷한 값들을 "Application ID"와 "Application Secret"으로 제공하고 있습니다.

하지만, 인증 서비스에 있어 페이스북이 좀 더 다양한 기능들을 제공해 주고 있는데요. 개인적으로 마음에 드는 것이 SSO(Single-Sign-on) 기능과 "Deauthorize URL" 등록 기능입니다.

우선, ASP.NET에서의 SSO 구현은 다음의 웹 사이트에서 자세히 설명하고 있습니다.

Facebook Platform's OAuth 2.0 Protocol and ASP.NET MVC
; http://amirrajan.net/Blog/asp-mvc-and-facebook-single-sign-on

위와 같이 서버 측에서 제어하는 것도 가능한데요. 페이스북은 클라이언트의 JavaScript에서도 SSO 인증이 되도록 하는 js 파일을 공개해 주고 있습니다. 이에 대해서는 다음의 글에서 "Single Sign-on" 부분을 참고하실 수 있습니다.

Facebook for Websites
- Single Sign-on
; http://developers.facebook.com/docs/guides/web

위의 글에서 설명된 것처럼 SSO 구현은 여러분들의 웹 사이트에 다음과 같은 HTML 및 Javascript 링크와 코드를 추가해 주는 것으로 간단하게 적용될 수 있습니다.

<div id="fb-root"></div>
<script src="http://connect.facebook.net/en_US/all.js"></script>
<script>
  FB.init({appId: '[응용 프로그램 등록 시 받는 Application ID]', status: true, cookie: true, xfbml: true});
  FB.Event.subscribe('auth.sessionChange', function(response) {
    if (response.session) 
    {
        // 로그인 상태로 판정될 때 실행되는 코드
    } else {
        // 로그아웃 상태로 판정될 때 실행되는 코드
    }
  });
</script>

<fb:login-button></fb:login-button> <!-- 로그인 버튼 이미지 -->


<fb:login-button />으로 표시되는 로그인 버튼 이미지를 사용자가 클릭하면 페이스북 측에서 제공하는 로그인 화면이 팝업창으로 뜨고 사용자는 페이스북 로그인 하듯이 사용자 정보를 입력합니다. 물론, 웹 사이트 측에는 트위터에서 그랬던 것처럼 사용자 계정에 대해서는 어떠한 정보도 알려주지 않고 access_token 값 만을 넘겨주게 됩니다.

FB.init / FB.Event.subscribe의 자바스크립트 역할은 간단합니다. 만약, 사용자가 Facebook 로그인에 대해서 "로그인 상태 유지(Remember Me)"를 체크해 놓고 로그인 한 적이 있다면, 위의 자바 스크립트 함수를 포함하는 웹 사이트를 방문하면 초기 FB... 메서드 실행 시에 페이스북 사이트로부터 정보를 조회해서 로그인 처리를 하게 됩니다. 반대로, 현재 로그인 해서 사용하고 있는 웹 사이트와는 별개의 창으로 떠 있는 웹 브라우저에서 방문중인 페이스북에서 로그아웃을 하는 경우에도, 위의 자바스크립트가 실행되면 '로그 아웃' 부분에 해당하는 자바 스크립트 코드가 실행될 수 있습니다.

인증처리를 서버측에서 하느냐, 자바스크립트로 하느냐에 대해서는 장단점이 있습니다. 자바스크립트를 활용하게 되면 서버 측에서 지저분하게 인증 관련 코드를 넣을 필요가 없어서 좋긴 하지만 대부분의 경우 다시 화면을 refresh 해주는 코드를 자바스크립트에 넣어주어서 화면 깜빡임이 발생하게 됩니다.

SSO를 조금이라도 아시는 분들이라면, 그 방법이 쿠키임을 짐작하실 테고, 그렇다면 쿠키가 적용되는 도메인 영역이 지정되어야 할 텐데, 페이스북은 어떻게 이를 판단할까요? 네... 이 부분은 응용 프로그램 등록화면에서 쿠키가 적용될 도메인 영역을 다음과 같이 미리 지정해 주었어야 합니다.

integrate_facebook_auth_4.png

로그인 된 경우, 지정된 도메인 영역으로 다음과 같은 쿠키 설정이 추가됩니다.

fbs_[AppId]="access_token=[AppId]...&base_domain=[사이트 도메인]&expires=...[인증유효기간]...&secret=....&session_key=....&sig=....&uid=...";


페이스북 로그인 연동이 적용된 제 웹 사이트의 경우에 풀어보면 다음과 같습니다.

fbs_[AppId]="...[이하 아래의 값들이 개행문자 없이 나열됨]..."

access_token: ...[생략]...
base_domain: www.sysnet.pe.kr
expires: 1290085200
secret: ...[생략]...
session_key: ...[생략]...
sig: ...[생략]...
uid: ...[생략]...
name : SeongTae Jeong
email: ...[생략]...
website: https://www.sysnet.pe.kr

위의 정보에서 중요한 것은 "access_token" 값입니다. 그 값을 기반으로 이전에 빌드해 둔, FacebookAPI.dll을 이용하여 페이스북 웹 사이트로부터 제공되는 다양한 API를 접근하게 되는데, 이와 관련해서 자세한 개발 관련 정보는 아래의 웹 페이지에서 찾아볼 수 있습니다.

Graph API Overview
; http://developers.facebook.com/docs/api

Graph API Reference
; http://developers.facebook.com/docs/reference/api/

예를 들어, "사용자" 정보를 조회하고 싶다면, "Graph API Reference"에서 살펴보고 http://developers.facebook.com/docs/reference/api/user에서 설명되고 있는 것임을 인식하고, 그 페이지에 제시된 쿼리 URL을 아래와 같이 찾을 수 있습니다.

User
A user profile. This object supports Real-Time Updates for all properties except the verified property.

예
https://graph.facebook.com/me (current user) 

도메인 까지의 쿼리 주소는 FacebookAPI에서 붙여주기 때문에 뒤의 "/me"만 붙여서 다음과 같이 조회를 해 올 수 있습니다.

Facebook.FacebookAPI api = new Facebook.FacebookAPI(...[쿠키에서 구해온 access_token 값]...);
Facebook.JSONObject me = api.Get("/me");

그런 후, 반환되는 것은 해당 명세서에 보이는 것 처럼 id, first_name,... 등등의 값을 다음과 같이 조회해 올 수 있습니다.

string userName = me.Dictionary["first_name"].String;
string userId = me.Dictionary["id"].String;

여기까지 기본적인 인증 방법 및 사용법 설명은 끝입니다.




부가적으로, 더 설명드려야 하는 것이 있다면 "사용자 정보" 조회 등에 대해서 일부 정보는 반드시 사용자로부터의 허락을 받아야만 가져올 수 있다는 점입니다. (이 부분에 대해서는 페이스북 개발자에게 정말 박수를 쳐주고 싶습니다. ^^)

예를 들면, 위의 api.Get("/me"); 코드를 통해서 사용자 정보를 조회할 때 email을 조회하면 빈 문자열이 반환되는 것을 확인할 수 있습니다. 왜냐하면, email 정보는 "사용자"가 해당 응용 프로그램이 조회해도 좋다는 허락을 해줘야 하기 때문입니다.

이에 대해서는 "http://developers.facebook.com/docs/reference/api/user"에서도 다음과 같이 명시되어 있습니다.

email : Requires email permission

만약, 여러분들의 웹 애플리케이션(또는 응용 프로그램)에서 사용자의 이메일 정보가 필요하다면 명시적으로 요청을 해야 합니다. 위에서 설명한 "<fb:login-button />" 버튼을 이용한 경우 다음과 같이 간단하게 처리가 됩니다.

<fb:login-button perms="...[요구되는 정보를 위한 권한 문자열]..."></fb:login-button>

제 웹 사이트의 경우 사용자 정보에서 "email"과 "user_website" 정보 2가지를 요구하기 때문에 다음과 같이 설정되어 있고,

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

사용자는 최초 페이스북 로그인 시에 다음과 같이 확인을 받게 됩니다.

integrate_facebook_auth_5.png




더욱 훌륭한 것은, 이메일 정보의 보호입니다. 사실, 자신이 사용하려는 웹 사이트가 이메일 정보를 요구한다면 "줄 수밖에 없는 상황"이 되어버리는 데요. (누군들, 사이트 약관을 읽어보고 정보 제공에 동의하고 싶겠습니까?) 페이스북은 이메일 주소를 외부적으로 노출되는 전용 이메일 계정을 별도로 제공해주는 데요. 이름하여 "proxied email"입니다. (사용자는 페이스북의 계정 정보 설정에서 이런 경우 "proxied email" 주소를 제공할 것인지, 실제 이메일 주소를 제공할 것인지를 선택할 수가 잇습니다.)

그래서, 페이스북 이외의 다른 응용 프로그램들은 원래의 사용자 이메일 정보를 알 수는 없고 페이스북에서 중계해주는 "proxied email" 주소만을 알 수 있습니다. 이에 대해서는 다음의 글에서 자세히 설명해 주고 있으니 참고하세요. ^^

Facebook App Notifications Moving to Your E-mail Inbox
; http://mashable.com/2010/01/20/facebook-applications-email/

사용자 정보 보호에 이런 세심함을 보여주는 웹 사이트를 보고 있노라니... 오히려 사용자 정보를 팔아먹는 못된 사이트들과 비교가 되는군요. ^^;




대부분의 외부 웹 응용 프로그램에서 취하는 형태가 바로 "페이스북 연동"일 것입니다. 기존 웹 애플리케이션 계정 정책에 페이스북 계정을 연동하기 위해서는 쿠키로부터 uid 값을 취해서 현재 "외부 웹 응용 프로그램"에 로그인한 사용자 계정과 연관지어 보관해 두어야 합니다.

access_token: ...[생략]...
base_domain: www.sysnet.pe.kr
expires: 1290085200
secret: ...[생략]...
session_key: ...[생략]...
sig: ...[생략]...
uid: 10302394932804
name : SeongTae Jeong
email: ...[생략]...
website: https://www.sysnet.pe.kr

이렇게 되면, 나중에는 페이스북 계정연동으로 인한 DB 자료들이 늘어나게 될 텐데요. 재미있는 점은, 사용자는 언제든지 아래에서 보는 것처럼 페이스북 웹 사이트로부터 여러분들의 웹 사이트와의 연동을 해제할 수 있다는 것입니다.

integrate_facebook_auth_6.png

따라서 이런 상황이 되면 웹 사이트 DB 에는 더 이상 쓸모없는 페이스북 관련 연동 정보가 쌓여만 가는 상황이 되는 것입니다.

정상적이라면, 이런 경우 페이스북 측에서 "어플리케이션 제거" 링크를 사용자가 누를 때 해당 웹 사이트에 통지를 해주면 좋을 텐데요. 바로 이 기능을 위해서 응용 프로그램 설정 화면에서 "Deauthorize URL" 입력란이 있는 것입니다.

integrate_facebook_auth_7.png

위에서는 "/user/removeuser.aspx" 웹 페이지를 부르도록 하고 있는데요. 페이스북은 사용자가 "어플리케이션 제거" 링크를 누르면 "removeuser.aspx" 호출 시에 POST 데이터에 여러 가지 정보를 넣어주는 데 이 중에서 "fb_sig_user" 값이 인증 시에 쿠키에 담겨 있던 "uid" 값이 되므로 사용자 정보를 DB에서 정상적으로 제거해 줄 수 있게 됩니다. 대략 다음과 같은 서버 측 코드를 구성해주면 됩니다.

public partial class removeuser : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        string userId = Request.Form["fb_sig_user"];

        if (string.IsNullOrEmpty(userId) == false)
        {
            ...[DB에서 제거]...
        }
    }
}

물론... 하필 사용자가 "어플리케이션 제거"를 할 때 여러분들의 웹 서버가 멈춰있다면... 어쩔 수 없겠군요. ^^



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

[연관 글]






[최초 등록일: ]
[최종 수정일: 6/28/2023]

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

비밀번호

댓글 작성자
 



2010-12-14 02시40분
[ㅠㅠ] 인증해제콜백 주소는 어플리케이션 사용자가 어플리케이션을 제거했을때 저 주소로 콜백 해주는 거죠?
저는 설정을 해놓았는데 해당 주소로 콜이 오지 않네요...
잘 되고 계시나요?
[guest]
2010-12-14 03시23분
저게... 테스트하기가 은근히 귀찮아서 지금 당장 해보기는 좀 그렇군요. ^^ 위의 글을 쓸 당시에는 잘 되었습니다. 2번 정도 정상적으로 테스트해서 호출되는 것을 확인했습니다. 직접 제 사이트에 테스트를 해보시겠어요? 여기서 로그인한 다음에 페이스북에서 해제하시고요. 저에게 ID 알려주시면 제 DB에서 삭제가 되었는지 말씀해드리겠습니다. ^^
정성태
2012-08-23 01시48분
[guest] 질문있습니다.
어떤 목적의 사이트에 접속하면 처음에 자동으로 페이스북 로그인 화면으로 뜨도록은 했습니다.
이제 거기서 페이스북에 로그인을 정상적으로 하게 되면 어떤 인증값을 받아서 처음 목적의 사이트에 로그인이 된 상태로 뜨도록 해야 합니다.
어떻게 해야 하나요? jsp로 구현을 해야 합니다. 도와주세요. 부탁드립니다.
[guest]
2012-08-23 04시22분
글쎄요. 뭐라고 더 설명드려야 할지 모르겠군요. 위의 내용을 읽어보시면 그에 대한 내용이 나옵니다. 본문에서 기능 구현을 클라이언트 측 javascript로 했기 때문에 jsp나 asp.net 상관없이 적용할 수 있습니다.
정성태
2013-05-21 06시12분
정성태

1  2  [3]  4  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13561정성태2/20/20242060닷넷: 2218. C# - (예를 들어, Socket) 비동기 I/O에 대한 await 호출 시 CancellationToken을 이용한 취소파일 다운로드1
13560정성태2/19/20242092디버깅 기술: 195. windbg 분석 사례 - Semaphore 잠금으로 인한 Hang 현상 (닷넷)
13559정성태2/19/20242944오류 유형: 895. ASP.NET - System.Security.SecurityException: 'Requested registry access is not allowed.'
13558정성태2/18/20242177닷넷: 2217. C# - 최댓값이 1인 SemaphoreSlim 보다 Mutex 또는 lock(obj)를 선택하는 것이 나은 이유
13557정성태2/18/20241921Windows: 258. Task Scheduler의 Author 속성 값을 변경하는 방법
13556정성태2/17/20241969Windows: 257. Windows - Symbolic (hard/soft) Link 및 Junction 차이점
13555정성태2/15/20242116닷넷: 2216. C# - SemaphoreSlim 사용 시 주의점
13554정성태2/15/20241861VS.NET IDE: 189. Visual Studio - 닷넷 소스코드 디컴파일 찾기가 안 될 때
13553정성태2/14/20241943닷넷: 2215. windbg - thin/fat lock 없이 동작하는 Monitor.Wait + Pulse
13552정성태2/13/20241896닷넷: 2214. windbg - Monitor.Enter의 thin lock과 fat lock
13551정성태2/12/20242089닷넷: 2213. ASP.NET/Core 웹 응용 프로그램 - 2차 스레드의 예외로 인한 비정상 종료
13550정성태2/11/20242208Windows: 256. C# - Server socket이 닫히면 Accept 시켰던 자식 소켓이 닫힐까요?
13549정성태2/3/20242504개발 환경 구성: 706. C# - 컨테이너에서 실행하기 위한 (소켓) 콘솔 프로젝트 구성
13548정성태2/1/20242335개발 환경 구성: 705. "Docker Desktop for Windows" - ASP.NET Core 응용 프로그램의 소켓 주소 바인딩(IPv4/IPv6 loopback, Any)
13547정성태1/31/20242085개발 환경 구성: 704. Visual Studio - .NET 8 프로젝트부터 dockerfile에 추가된 "USER app" 설정
13546정성태1/30/20241949Windows: 255. (디버거의 영향 등으로) 대상 프로세스가 멈추면 Socket KeepAlive로 연결이 끊길까요?
13545정성태1/30/20241859닷넷: 2212. ASP.NET Core - 우선순위에 따른 HTTP/HTTPS 호스트:포트 바인딩 방법
13544정성태1/30/20241883오류 유형: 894. Microsoft.Data.SqlClient - Could not load file or assembly 'System.Security.Permissions, ...'
13543정성태1/30/20241882Windows: 254. Windows - 기본 사용 중인 5357 포트 비활성화는 방법
13542정성태1/30/20241913오류 유형: 893. Visual Studio - Web Application을 실행하지 못하는 IISExpress - 두 번째 이야기
13541정성태1/29/20241973VS.NET IDE: 188. launchSettings.json의 useSSL 옵션
13540정성태1/29/20242078Linux: 69. 리눅스 - "Docker Desktop for Windows" Container 환경에서 IPv6 Loopback Address 바인딩 오류
13539정성태1/26/20242365개발 환경 구성: 703. Visual Studio - launchSettings.json을 이용한 HTTP/HTTPS 포트 바인딩
13538정성태1/25/20242419닷넷: 2211. C# - NonGC(FOH) 영역에 .NET 개체를 생성파일 다운로드1
13537정성태1/24/20242512닷넷: 2210. C# - Native 메모리에 .NET 개체를 생성파일 다운로드1
13536정성태1/23/20242597닷넷: 2209. .NET 8 - NonGC Heap / FOH (Frozen Object Heap) [1]
1  2  [3]  4  5  6  7  8  9  10  11  12  13  14  15  ...