API REST cho trang web sử dụng Facebook để xác thực


86

Chúng tôi có một trang web mà cách duy nhất để đăng nhập và xác thực chính bạn với trang đó là sử dụng Facebook (đây không phải là lựa chọn của tôi). Lần đầu tiên bạn đăng nhập bằng Facebook, một tài khoản sẽ tự động được tạo cho bạn.

Bây giờ chúng tôi muốn tạo một ứng dụng iPhone cho trang web của mình và cũng là một API công khai để những người khác sử dụng dịch vụ của chúng tôi.

Câu hỏi này là về cách xác thực với trang web của chúng tôi từ ứng dụng / API và được chia thành 2 phần:

  1. Cách chính xác để xử lý xác thực REST từ một API đến một trang web chỉ sử dụng Facebook OAuth làm phương thức xác thực là gì?

    Tôi đã đọc và nghiên cứu rất nhiều về các phương pháp xác thực tiêu chuẩn cho REST API. Chúng tôi không thể sử dụng các phương pháp như Xác thực cơ bản qua HTTPS vì không có thông tin xác thực cho người dùng như vậy. Một cái gì đó như thế này dường như chỉ dành cho việc xác thực các ứng dụng bằng API.

    Hiện tại, cách tốt nhất tôi có thể nghĩ là bạn nhấn / ủy quyền điểm cuối trên API của chúng tôi, nó chuyển hướng đến Facebook OAuth, sau đó chuyển hướng trở lại trang web và cung cấp 'mã thông báo' mà người dùng API có thể sử dụng để xác thực sau đó các yêu cầu.

  2. Đối với một ứng dụng chính thức mà chúng tôi tạo, chúng tôi không nhất thiết phải sử dụng API công khai theo cách tương tự. Sau đó, cách tốt nhất để nói chuyện với trang web của chúng tôi và xác thực người dùng là gì?

Tôi hiểu (tôi nghĩ) cách xác thực các ứng dụng của bên thứ 3 đang sử dụng API của chúng tôi, sử dụng khóa API (công khai) và khóa bí mật (riêng tư). Tuy nhiên, khi nói đến việc xác thực người dùng đang sử dụng ứng dụng, tôi khá bối rối về cách thực hiện khi cách duy nhất chúng tôi phải xác thực người dùng là Facebook.

Tôi cảm thấy như mình đang thiếu một cái gì đó rất rõ ràng hoặc không hiểu đầy đủ về cách hoạt động của các API REST công khai, vì vậy mọi lời khuyên và trợ giúp sẽ được đánh giá rất cao.


Tôi có câu hỏi tương tự tại stackoverflow.com/questions/30230482/… nói về một số câu hỏi này
JVK

Câu trả lời:


99

CẬP NHẬT: xem bên dưới

Tôi cũng đã suy nghĩ rất nhiều về câu hỏi này. Tôi vẫn chưa hoàn toàn rõ ràng nhưng đây là lộ trình tôi đang nghĩ đến. Tôi đang tạo API REST, một xác thực chỉ người dùng của tôi kết nối Facebook.

Trên CLIENT:

  1. Sử dụng API Facebook để đăng nhập và nhận mã OAUTH2.
  2. Trao đổi mã này để lấy mã thông báo truy cập.
  3. Trong mọi lệnh gọi tới API tùy chỉnh của mình, tôi sẽ bao gồm id người dùng Facebook và mã thông báo truy cập.

Trên API (đối với mọi phương pháp yêu cầu xác thực người dùng):

  1. Thực hiện yêu cầu đối với biểu đồ / tôi Facebook bằng cách sử dụng mã thông báo truy cập từ phía trên.
  2. Xác minh rằng id người dùng Facebook trả về khớp với id người dùng được chuyển đến API của tôi từ bên trên.
  3. Nếu mã thông báo truy cập đã hết hạn, cần có thông tin liên lạc bổ sung.

Tôi vẫn chưa kiểm tra điều này. Nó nghe như thế nào?

--- Cập nhật: ngày 27 tháng 7 năm 2014 để trả lời câu hỏi ---

Tôi chỉ sử dụng trao đổi ở trên một lần khi đăng nhập. Khi tôi xác định được người dùng nào đang đăng nhập, tôi tạo mã thông báo truy cập của riêng mình và mã thông báo đó được sử dụng từ thời điểm đó về sau. Vì vậy, luồng mới trông như thế này ...

Trên CLIENT:

  1. Sử dụng API Facebook để đăng nhập và nhận mã OAUTH2.
  2. Trao đổi mã này để lấy mã thông báo truy cập.
  3. Yêu cầu mã thông báo truy cập từ API của tôi , bao gồm mã thông báo Facebook làm thông số

Trên API

  1. Nhận yêu cầu mã thông báo truy cập.
  2. Thực hiện yêu cầu đối với biểu đồ / tôi Facebook bằng cách sử dụng mã thông báo truy cập facebook
  3. Xác minh rằng người dùng Facebook tồn tại và khớp với người dùng trong cơ sở dữ liệu của tôi
  4. Tạo mã thông báo truy cập của riêng tôi, lưu nó và trả lại cho khách hàng để sử dụng từ thời điểm này trở đi

Này, đó là một câu trả lời muộn, nhưng giải pháp của bạn dường như khắc phục được vấn đề mà tôi gặp phải trong câu trả lời đầu tiên của mình. Tất nhiên, bạn phải sử dụng HTTPS để không gửi cặp (id, mã thông báo) trên dây ở dạng văn bản rõ ràng. Nhưng có vẻ như nó sẽ hoạt động!
Olivier Lance

Tôi nghĩ thật tốt khi gọi / tôi trên máy chủ và tạo mã thông báo truy cập của riêng bạn, mã này sẽ được ứng dụng khách di động sử dụng.
Der_Meister

Tôi thấy rằng việc lưu trữ bí mật FB trong ứng dụng dành cho thiết bị di động là một việc làm không tốt. Facebook khuyên chỉ nên lưu trữ nó trên máy chủ của bạn. developers.facebook.com/docs/opengraph/using-actions/...
Der_Meister

Nếu chúng tôi gửi user_id và access_token đến máy chủ API mọi lúc (dưới dạng post / get params). Nó sẽ tạo ra lỗ hổng bảo mật nếu một số người có thể chặn kết nối?
Nathan Do

@NathanDo Sử dụng HTTPS giữa máy khách của bạn và máy chủ API và sẽ không có vấn đề gì nếu ai đó chặn kết nối (bỏ qua các lỗ hổng kiểu Heartbleed).
dcr

15

Đây là cách triển khai của tôi bằng cách sử dụng JWT (Mã thông báo web JSON), về cơ bản tương tự như câu trả lời được cập nhật của Chris. Tôi đã sử dụng Facebook JS SDK và JWT.

Đây là cách thực hiện của tôi.

  1. Khách hàng: Sử dụng Facebook JS SDK để đăng nhập và nhận mã thông báo truy cập.

  2. Khách hàng: Yêu cầu JWT từ API của tôi bằng cách gọi /verify-access-tokenđiểm cuối.

  3. MyAPI: Nhận mã thông báo truy cập, xác minh nó bằng cách gọi /međiểm cuối của API Facebook.

  4. MyAPI: Nếu mã thông báo truy cập hợp lệ, tìm người dùng từ cơ sở dữ liệu, đăng nhập người dùng nếu tồn tại. Tạo JWT với các trường bắt buộc làm trọng tải, đặt thời hạn, ký bằng khóa bí mật và gửi lại cho khách hàng.

  5. Máy khách: Lưu trữ JWT trong bộ nhớ cục bộ.

  6. Ứng dụng khách: Gửi mã thông báo (JWT từ bước 5) cùng với yêu cầu cho lệnh gọi API tiếp theo.

  7. MyAPI: xác thực mã thông báo bằng khóa bí mật, nếu mã thông báo hợp lệ, hãy đổi mã thông báo lấy một cái mới, gửi lại cho khách hàng cùng với phản hồi API. (Không có lệnh gọi API bên ngoài nào để xác minh mã thông báo tại đây sau đó) [nếu mã thông báo không hợp lệ / hết hạn, hãy yêu cầu khách hàng xác thực lại và lặp lại từ 1]

  8. Khách hàng Thay thế mã thông báo đã lưu trữ bằng mã mới và sử dụng nó cho lệnh gọi API tiếp theo. Sau khi hết hạn mã thông báo, mã thông báo hết hạn sẽ thu hồi quyền truy cập vào API.

Mỗi mã thông báo được sử dụng một lần.

Đọc thêm câu trả lời về bảo mật và JWT

JWT bảo mật như thế nào

Nếu bạn có thể giải mã JWT thì chúng an toàn như thế nào?

Mã thông báo web JSON (JWT) làm mã thông báo xác thực và nhận dạng người dùng


3
Tôi đoán số 3 là đúng hơn /debug_token, vì vậy bạn có thể kiểm tra xem mã thông báo có thực sự dành cho ứng dụng của bạn hay không.
Peppe LG

2
Không yêu cầu access_tokentrong Khách hàng. Sử dụng "quy trình làm việc mã". Vượt qua codeđể MyAPI và thực hiện một chuyến đi vòng lên Facebook để trao đổi codevới access_token. Này được giải thích nhiều triệt để ở đây: developers.facebook.com/docs/facebook-login/security
omikron

5

Tôi đang cố gắng trả lời câu hỏi tương tự và gần đây đã đọc rất nhiều ...

Tôi sẽ không có câu trả lời "" nhưng mọi thứ đang trở nên rõ ràng hơn đối với tôi. Bạn đã đọc những bình luận trong bài báo mình đề cập chưa? Tôi thấy chúng thực sự thú vị và hữu ích.

Kết quả là, dưới góc độ mọi thứ đã phát triển như thế nào kể từ khi bài báo đầu tiên được viết, đây là những gì tôi nghĩ tôi sẽ làm:

  • HTTPS ở mọi nơi - điều này cho phép bạn quên HMAC, ký, nonce, ...

  • Sử dụng OAuth2:

    • Khi các yêu cầu xác thực đến từ các ứng dụng / trang web của riêng tôi, hãy sử dụng 'thủ thuật' này (hoặc một biến thể của nó) được mô tả trong câu trả lời cho bài viết được đề cập trước đây.

    • Trong trường hợp của tôi, tôi có hai loại người dùng: những người có thông tin đăng nhập / mật khẩu cổ điển và những người đã đăng ký với Facebook Connect.
      Vì vậy, tôi sẽ cung cấp một biểu mẫu đăng nhập thông thường với nút "Đăng nhập bằng Facebook". Nếu người dùng đăng nhập bằng thông tin đăng nhập "cổ điển" của mình, tôi chỉ cần gửi những thông tin này tới điểm cuối OAuth2 của mình bằng một grant_type=password.
      Nếu anh ấy chọn đăng nhập qua Facebook, tôi nghĩ đó sẽ là một quy trình gồm hai bước:

      • Đầu tiên, sử dụng Facebook iOS SDK để mở FBSession
      • Khi điều đó hoàn tất và ứng dụng được trao lại quyền kiểm soát, cần có cách để lấy ID Facebook cho người dùng đó. Tôi sẽ gửi riêng ID này đến điểm cuối OAuth2 của mình với một khoản trợ cấp mở rộng được máy chủ của tôi hiểu là "sử dụng ID người dùng FB".

Xin lưu ý rằng tôi vẫn đang nghiên cứu rất nhiều về tất cả những thứ này, vì vậy đó có thể không phải là một câu trả lời hoàn hảo ... thậm chí có thể không phải là một câu trả lời chính xác! Nhưng tôi nghĩ điều đó sẽ tạo ra một điểm khởi đầu tốt. Ý tưởng sử dụng "khoản trợ cấp mở rộng" để xác thực Facebook có thể liên quan đến việc phải đăng ký nó để thực hiện mọi việc đúng cách? Tôi không chắc lắm.

Dù sao, tôi hy vọng tôi có thể giúp bạn một chút, và ít nhất nó có thể bắt đầu một cuộc thảo luận để tìm ra giải pháp tốt nhất cho vấn đề này :)

Cập nhật
Đăng nhập Facebook không phải là một giải pháp như đã chỉ ra trong các nhận xét: bất kỳ ai cũng có thể gửi một ID người dùng tùy ý và đăng nhập với tư cách người dùng này trên API.

Làm như thế này thì sao:

  • Hiển thị biểu mẫu đăng nhập có nút "Đăng nhập Facebook"
  • Nếu phương thức đăng nhập này được chọn, hãy hành động giống như Facebook SDK: mở một trang web từ máy chủ xác thực của bạn, máy chủ này sẽ bắt đầu đăng nhập Facebook.
  • Khi người dùng đã đăng nhập, Facebook sẽ sử dụng URL chuyển hướng của bạn để xác nhận; làm cho URL đó trỏ đến một điểm cuối khác của máy chủ xác thực của bạn (có thể có thêm một tham số cho biết cuộc gọi đến từ một ứng dụng?)
  • Khi điểm cuối xác thực được nhấn, xác thực có thể xác định người dùng một cách an toàn, giữ lại ID người dùng FB / Phiên FB của họ và trả lại mã thông báo truy cập cho ứng dụng của bạn bằng cách sử dụng lược đồ URL tùy chỉnh, giống như SDK Facebook sẽ làm

Trông tốt hơn?


1
Cảm ơn bạn đã trả lời của bạn! Tôi đã nghĩ về hầu hết những gì bạn nói nhưng mối quan tâm chính của tôi khi sử dụng FB iOS SDK và sau đó gửi ID người dùng Facebook là sẽ không dễ dàng gửi bất kỳ ID nào bạn muốn đến điểm cuối API của bạn và tuyên bố là người dùng khác? Đây là nơi tôi thường bị mắc kẹt ..
Adam

Thật! Tôi thật ngu ngốc khi không nghĩ đến điều đó ... Vì vậy, giải pháp phải thông qua máy chủ xác thực của riêng bạn bằng cách nào đó ...
Olivier Lance

Tôi đã cập nhật câu trả lời của mình với một ý tưởng giải pháp khác ... nhưng chỉ cần nhận ra rằng bạn đã đề cập đến nó trong câu hỏi ban đầu của mình! Tôi không thể nhìn thấy bất cứ thứ gì vào lúc này ...
Olivier Lance
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.