passport.js RESTful 인증


156

웹 인터페이스 대신 RESTful API를 통해 passport.js를 사용하여 인증 (예 : 로컬 및 Facebook)을 어떻게 처리합니까?

특정 문제는 콜백에서 RESTful 응답 (JSON)으로의 데이터 전달과 일반적인 res.send ({data : req.data}) 사용, Facebook으로 리디렉션되는 초기 / login 엔드 포인트 설정 (/ login은 JSON 응답이 아니기 때문에 AJAX를 통해 액세스됩니다. 콜백을 통해 Facebook으로 리디렉션됩니다.

https://github.com/halrobertson/test-restify-passport-facebook을 찾았 지만 이해하는 데 문제가 있습니다.

또한 passport.js는 인증 자격 증명을 어떻게 저장합니까? 서버 (또는 서비스입니까?)는 MongoDB에 의해 지원되며 자격 증명 (로그인 및 pw의 솔 티드 해시)이 거기에 저장 될 것으로 예상하지만 passport.js에 이러한 유형의 기능이 있는지 모르겠습니다.


당신이 노드에 익숙하기 때문에, 쉽게 시작하고 체크 아웃 예제 애플리케이션 에 대한을 passport-facebook. 작동이 끝나면 다음 단계는 Passport의 작동 방식과 자격 증명을 저장하는 방식을 이해하는 것입니다. Restify에 접선 ( 여기에서 보는 마지막 단계 중 하나가 될 것입니다 당신이 언급 한의 업데이트 된 버전) (또는 익스프레스에서 REST 인터페이스를 구현할 수 있습니다).
robertklep 2013 년

답변:


314

여기에는 많은 질문이 있으며 Node 및 passport.js의 맥락에서 질문이 있지만 실제 질문은 특정 기술로이를 수행하는 방법보다 워크 플로에 관한 것 같습니다.

보안 강화를 위해 약간 수정 된 @Keith 예제 설정을 사용해 보겠습니다.

  • 의 웹 서버 https://example.com는 단일 페이지 Javascript 클라이언트 앱을 제공합니다.
  • 의 RESTful 웹 서비스는 https://example.com/api리치 클라이언트 앱에 서버 지원을 제공합니다.
  • Node 및 passport.js에서 구현 된 서버.
  • 서버에는 "users"테이블이있는 데이터베이스 (모든 종류)가 있습니다.
  • 사용자 이름 / 암호 및 Facebook Connect가 인증 옵션으로 제공됩니다.
  • 리치 클라이언트는 REST 요청을 https://example.com/api
  • 에서 웹 서비스를 사용 https://example.com/api하지만 웹 서버에 대해 알지 못하는 다른 클라이언트 (예 : 전화 앱)가있을 수 있습니다 https://example.com.

보안 HTTP를 사용하고 있습니다. 이것은 암호 및 인증 토큰과 같은 민감한 정보가 클라이언트와 서버간에 전달되기 때문에 공개적으로 사용할 수있는 모든 서비스에 필수라고 생각합니다.

사용자 이름 / 비밀번호 인증

먼저 일반 이전 인증이 어떻게 작동하는지 살펴 보겠습니다.

  • 사용자가 연결 https://example.com
  • 서버는 초기 페이지를 렌더링하는 풍부한 Javascript 애플리케이션을 제공합니다. 페이지에 로그인 양식이 있습니다.
  • 이 단일 페이지 앱의 많은 섹션은 사용자가 로그인하지 않았기 때문에 데이터로 채워지지 않았습니다. 이러한 모든 섹션에는 "로그인"이벤트에 대한 이벤트 리스너가 있습니다. 이 모든 것은 클라이언트 측 항목이며 서버는 이러한 이벤트를 알지 못합니다.
  • 사용자가 자신의 로그인과 비밀번호를 입력하고 제출 버튼을 누르면 자바 스크립트 핸들러가 클라이언트 측 변수에 사용자 이름과 비밀번호를 기록합니다. 그런 다음이 핸들러는 "로그인"이벤트를 트리거합니다. 다시 말하지만, 이것은 모두 클라이언트 측 작업이며 자격 증명은 아직 서버로 전송되지 않았습니다 .
  • "login"이벤트의 리스너가 호출됩니다. 이제 이들 각각은 https://example.com/api페이지에서 렌더링 할 사용자 특정 데이터를 얻기 위해 하나 이상의 요청을 RESTful API로 보내야 합니다. RESTful 서비스는 한 요청에서 다음 요청까지 클라이언트 상태를 유지할 수 없기 때문에 웹 서비스에 보내는 모든 단일 요청에는 HTTP 기본 인증 의 형태로 사용자 이름과 비밀번호가 포함됩니다 . 웹 서비스가 보안 HTTP에 있기 때문에 암호는 전송 중에 안전하게 암호화됩니다.
  • 의 웹 서비스는 https://example.com/api각각 인증 정보가 포함 된 개별 요청 을 수신합니다. 각 요청의 사용자 이름과 비밀번호는 사용자 데이터베이스에 대해 확인되며 올바른 경우 요청 된 함수가 실행되고 데이터가 JSON 형식으로 클라이언트에 반환됩니다. 사용자 이름과 암호가 일치하지 않으면 401 HTTP 오류 코드 형식으로 클라이언트에 오류가 전송됩니다.
  • 클라이언트가 모든 요청에 ​​사용자 이름과 비밀번호를 보내도록하는 대신 사용자 이름과 비밀번호를 가져와 토큰으로 응답하는 "get_access_token"기능을 RESTful 서비스에 사용할 수 있습니다. 토큰은 고유하고 일부 만료가있는 일종의 암호화 해시입니다. 관련된 날짜. 이러한 토큰은 각 사용자와 함께 데이터베이스에 저장됩니다. 그런 다음 클라이언트는 후속 요청에서 액세스 토큰을 보냅니다. 그러면 사용자 이름과 암호 대신 데이터베이스에 대해 액세스 토큰의 유효성이 검사됩니다.
  • 전화 앱과 같은 비 브라우저 클라이언트 응용 프로그램은 위와 동일하게 사용자에게 자격 증명을 입력하도록 요청한 다음 웹 서비스에 대한 모든 요청과 함께 자격 증명 (또는 생성 된 액세스 토큰)을 보냅니다.

이 예제에서 중요한 점은 RESTful 웹 서비스가 모든 요청에 ​​대해 인증을 요구 한다는 것 입니다.

이 시나리오에서 추가 보안 계층은 사용자 인증 외에 클라이언트 애플리케이션 권한을 추가합니다. 예를 들어 웹 서비스를 사용하는 웹 클라이언트, iOS 및 Android 앱이 모두있는 경우 인증 된 사용자가 누구인지에 관계없이 서버가 주어진 요청의 세 클라이언트 중 어느 것이인지 알 수 있도록 할 수 있습니다. 이를 통해 웹 서비스가 특정 기능을 특정 클라이언트로 제한 할 수 있습니다. 이를 위해 API 키와 비밀을 사용할 수 있습니다. 이에 대한 몇 가지 아이디어는 이 답변 을 참조하십시오 .

Facebook 인증

Facebook을 통한 로그인에는 제 3자인 Facebook 자체가 있기 때문에 위의 워크 플로는 Facebook 연결에서 작동하지 않습니다. 로그인 절차를 수행하려면 사용자가 당사의 통제를 벗어난 자격 증명을 입력하는 Facebook 웹 사이트로 리디렉션되어야합니다.

그럼 상황이 어떻게 변하는 지 봅시다 :.

  • 사용자가 연결 https://example.com
  • 서버는 초기 페이지를 렌더링하는 풍부한 Javascript 애플리케이션을 제공합니다. 페이지에는 "페이스 북으로 로그인"버튼이 포함 된 로그인 양식이 있습니다.
  • 사용자가 (예 :)로 리디렉션되는 링크 인 "Facebook으로 로그인"버튼을 클릭합니다 https://example.com/auth/facebook.
  • https://example.com/auth/facebook경로가 passport.js에 의해 처리합니다 (참조 문서 )
  • 사용자가 볼 수있는 것은 페이지가 변경되고 이제 웹 애플리케이션에 로그인하고 권한을 부여해야하는 Facebook 호스팅 페이지에 있다는 것입니다. 이것은 완전히 우리가 통제 할 수없는 것입니다.
  • 페이스 북은 지금 우리가있는 다음 예제에서는 passport.js 설치, 구성하는 콜백 URL로 다시 리디렉션 있도록 페이스 북의 사용자가 로그인하고, 우리의 응용 프로그램에 권한을 부여 문서 것이 있다https://example.com/auth/facebook/callback
  • https://example.com/auth/facebook/callback경로에 대한 passport.js 핸들러 는 사용자의 이메일 주소를 포함하여 Facebook 액세스 토큰과 Facebook에서 일부 사용자 정보를 수신하는 콜백 함수를 호출합니다.
  • 이메일을 사용하여 데이터베이스에서 사용자를 찾고 Facebook 액세스 토큰을 저장할 수 있습니다.
  • Facebook 콜백에서 마지막으로 수행하는 작업은 리치 클라이언트 애플리케이션으로 다시 리디렉션하는 것이지만 이번에는 클라이언트가 사용할 수 있도록 사용자 이름과 액세스 토큰을 클라이언트에 전달해야합니다. 이것은 여러 가지 방법으로 수행 할 수 있습니다. 예를 들어 Javascript 변수는 서버 측 템플릿 엔진을 통해 페이지에 추가 될 수 있으며 그렇지 않으면이 정보와 함께 쿠키가 반환 될 수 있습니다. (처음에 제안했듯이 URL에이 데이터를 전달할 때 보안 문제를 지적한 @RyanKimber에게 감사드립니다).
  • 이제 단일 페이지 앱을 한 번 더 시작하지만 클라이언트에는 사용자 이름과 액세스 토큰이 있습니다.
  • 클라이언트 응용 프로그램은 "로그인"이벤트를 즉시 트리거하고 응용 프로그램의 다른 부분이 웹 서비스에서 필요한 정보를 요청하도록 할 수 있습니다.
  • 로 전송되는 모든 요청 https://example.com/api에는 인증을위한 Facebook 액세스 토큰 또는 REST API의 "get_access_token"함수를 통해 Facebook의 토큰에서 생성 된 애플리케이션 자체 액세스 토큰이 포함됩니다.
  • OAuth는 로그인을 위해 웹 브라우저가 필요하기 때문에 브라우저가 아닌 앱은 여기에서 조금 더 어렵습니다. 전화 또는 데스크톱 앱에서 로그인하려면 브라우저를 시작하여 Facebook으로 리디렉션해야합니다. 브라우저가 일부 메커니즘을 통해 Facebook 액세스 토큰을 애플리케이션에 다시 전달하는 방법이 필요합니다.

나는 이것이 대부분의 질문에 답하기를 바랍니다. 물론 Facebook을 Twitter, Google 또는 기타 OAuth 기반 인증 서비스로 대체 할 수 있습니다.

나는 누군가가 이것을 다루는 더 간단한 방법을 가지고 있는지 알고 싶습니다.


5
귀하의 자세한 답변에 감사드립니다. 한 가지 질문 Every single request they send to the web service will include the username and password만하시면 you can have a "get_access_token" function in your RESTful service됩니다. REST가 상태 비 저장이어야한다고 말하는 것은 모순되는 것처럼 보이지만, 액세스 토큰을 저장하는 행위는 이제 서버가 상태 저장 상태임을 의미하므로 서버 측에 액세스 토큰을 저장하는 것은 괜찮습니다. 이에 대한 설명이나 정당화에 감사드립니다. 감사! :)
ryanrhee 2013 년

6
상태 비 저장 요구 사항에 대해 생각할 때 클라이언트와의 특정 세션에 대한 상태를 생각합니다. 적어도 "세션 상태"가 아닌 "상태"인 암호 또는 액세스 토큰과 같이 데이터베이스에 사용자와 관련된 데이터를 저장하는 것을 볼 수 없습니다. 서버는 분명히 사용자가 누구인지 그리고 그들의 암호를 알아야하지만 이것은 세션과 연관되지 않은 애플리케이션 데이터입니다. 즉, 많은 사람들이 RESTful 서비스에서 쿠키를 사용하므로 REST 사양을 얼마나 엄격하게 준수할지는 실제로 각 구현 자에게 달려 있습니다.
Miguel

1
@Dexter : 전통적인 로그인의 경우 사용자가 양식에 사용자 이름과 비밀번호를 입력하고 제출 버튼을 누르면이 정보가 웹 서버에 게시됩니다. 이 경우 사용자는 양식을 작성하고 Javascript 처리기 제출 (제출 버튼의 onClick 이벤트)을 누르면 데이터를 캡처하여 클라이언트 컨텍스트에 보관합니다. 예를 보여줄 준비가되어 있지는 않지만 내 블로그에서이 자습서의 두 번째 부분을 살펴 보겠습니다. 여기서 수행 방법을 보여줄 것입니다. blog.miguelgrinberg.com/post/…
Miguel

2
이것은 매우 잘 고안된 글이지만 한 가지 중요한 감독 또는 오류가 포함되어 있습니다. Facebook 로그인 (또는 Github, twitter 등)을 처리 할 때, 토큰을 쿠키로 클라이언트에게 다시 전달한 다음 발견되면 클라이언트 측에서 쿠키를 삭제하는 것이 훨씬 선호됩니다. 토큰을 URL 문자열의 일부로 전달하면이 URL이 브라우저 기록에 추가되고 (부적절하게 처리되는 경우) 브라우저에서이 URL을 요청할 수 있습니다. 토큰을 표시합니다. 그런 다음 URL을 복사 한 사람은 누구나 애플리케이션에서이 사용자를 스푸핑 할 수 있습니다.
Ryan Kimber

1
@Nathan : https를 통한 기본 인증은 안전하므로 허용되는 메커니즘입니다.
미구엘

11

@Miguel의 설명을 각 경우에 완전한 흐름으로 매우 감사하지만, Facebook 인증 부분에 일부를 추가하고 싶습니다.

Facebook은 클라이언트 측에서 직접 액세스 토큰을 가져 오는 데 사용할 수 있는 Javascript SDK 를 제공하며,이 토큰은 서버로 전달되고 Facebook에서 모든 사용자 정보를 추가로 가져 오는 데 사용됩니다. 따라서 기본적으로 리디렉션이 필요하지 않습니다.

또한 모바일 애플리케이션에 대해서도 동일한 API 엔드 포인트를 사용할 수 있습니다. Facebook 용 Android / iOS SDK를 사용하고 클라이언트 쪽에서 Facebook access_token을 가져와 서버에 전달하면됩니다.

설명 된 상태 비 저장 특성 과 관련하여 get_access_token을 사용하여 토큰을 생성하고 클라이언트에 전달하면이 토큰도 서버에 저장됩니다. 그래서 그것은 세션 토큰만큼 좋으며 이것이 상태 저장을 만든다고 생각합니까?

내 2 센트 ..


1
이렇게하면 페이스 북을 사용하여 한 페이지 만 ajax 인증을 할 수 있기 때문에 이것은 매우 중요합니다. 토큰은 세션 인증과 동일하게 안전하며, 유일한 차이점은 토큰을 다른 도메인으로 전달할 수 있으며 세션은 하나의 특정 도메인에서만 사용된다는 것입니다. expressjs와 패스포트를 사용할 때 상태를 저장하는 API를 만들고 세션 인증을 사용할 수 있습니다.
jperelli 2014

javascript api는 Facebook에 대한 작업을 수행하기 위해 사용자를 인증하려는 경우 유용하지만 내가 말할 수있는 한 서버 / 데이터베이스에 대해 사용자를 확인하려는 경우 그 자체로는 쓸모가 없습니다.
James Westgate 2014

4
위에서 Miguel이 설명한 방법을 사용할 수도 있지만 인증 콜백에서 클라이언트를 리디렉션 할 때 고유 한 JWT 토큰을 쿠키로 발급 할 수 있습니다. 이를 통해 두 가지 장점을 모두 활용할 수 있습니다. 단일 페이지 애플리케이션은 한 가지 유형의 인증 (JWT)에만 관심을 가질 수 있으며 동일한 수준의 보안을 유지하고 소셜 로그인을 사용할 필요없이 유연하게 지원할 수 있습니다. 각 소셜 네트워크 (Facebook, Twitter, LinkedIn, Google 등)에 대한 특정 JavaScript API. 또한 사용자 이름 / 암호 및 REST 액세스에 대한 AJAX 스타일 지원을 유지할 수 있습니다.
Ryan Kimber

Facebook Javascript SDK는 현재 Chrome iOS에서 작동하지 않습니다. 일부에게는 문제가 될 수 있습니다.
demisx

@RyanKimber는이 같이 이루어집니다 작은 자식의 repo 또는 유사한을 작성할 수 있습니다 완전히 붙어 예를 들어 메신저
사이먼 Dragsbæk

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.