2011-08-29 62 views
7

Chúng tôi có thiết lập ứng dụng đường ray sử dụng tính năng xác thực Facebook để cho phép đăng nhập qua xác thực facebook. Chúng tôi cũng có ứng dụng dành cho thiết bị di động hiện đang sử dụng xác thực http để đăng nhập vào ứng dụng đường ray bằng cách chuyển tên người dùng & mật khẩu hoặc bằng cách chuyển vào mã xác thực http. Điều này tất cả các công trình lớn cho đến nay.Cách sử dụng xác thực http với mã thông báo omniauth tùy chọn như mã thông báo xác thực

Ứng dụng di động cũng có khả năng xác thực bằng chính facebook và nhận mã thông báo người dùng facebook trực tiếp giữa chính nó và facebook.

Tôi muốn thu hẹp khoảng cách này để nếu người dùng đăng nhập từ ứng dụng di động qua facebook và có mã thông báo facebook, hãy cho phép mã thông báo facebook được sử dụng làm xác thực trên ứng dụng đường ray như thể họ đã nhận được nó từ facebook thông qua trình duyệt.

Kết quả cuối cùng sẽ là ứng dụng di động có thể đăng nhập người dùng trong qua:

1) tên người dùng/mật khẩu hoặc 2) http authentication thẻ hoặc 3) omniauth (facebook) token

Ngoài ra, trong trường hợp 3), nếu người dùng chưa tồn tại trên ứng dụng đường ray, sẽ cần phải tạo người dùng - thực hiện điều đó ngay bây giờ với xác thực bên trình duyệt để có thể không còn gì để làm.

Làm cách nào để tôi có thể thực hiện điều này tốt nhất trong cấu trúc dự kiến?

Trả lời

10

Chỉ làm việc này, nhưng chưa bao giờ thấy giải pháp đầu cuối.

Địa chỉ này điểm 3. 1 & 2 có thể dễ dàng thực hiện bằng cách đưa ra và ghi lại ở nơi khác.

Không quá khó để thêm auth FB vào ứng dụng web của bạn, hướng dẫn trên github cho omniauth và omniauth-facebook.

Tôi tin những điều sau đây là viết tắt một mình, mà không thực hiện tích hợp omniauth-facebook, nếu bạn muốn thực hiện theo cách đó. Điều này cũng tương tự như các cách tiếp cận khác. Ý tưởng của tôi là cố gắng sử dụng mô hình suy nghĩ kỹ càng nhất có thể.

Bạn sẽ cần đá quý fb_graph.

Trên máy khách di động, bạn xác thực với FB một cách thích hợp và đặt mã thông báo truy cập được trả về trong tiêu đề của các yêu cầu http của bạn. Tôi đã sử dụng tiêu đề fb_access_token. Cũng giống như auth cơ bản, bạn sẽ muốn gửi thông báo này qua SSL để tránh đánh hơi mã thông báo. Sử dụng tiêu đề cho phép tôi trao đổi auth cơ bản và xác thực FB mà không thay đổi yêu cầu, nhưng bạn có thể sử dụng tham số nếu bạn muốn.

Giải pháp này thực hiện một chiến lược bảo vệ dựa trên chiến lược bảo mật của Authenticatable. Sự khác biệt ở đây là thực tế rằng chiến lược này sử dụng một tiêu đề HTTP gọi là fb_access_token có chứa chuỗi mã thông báo truy cập facebook được truy xuất bằng ứng dụng di động.

Khi bạn biết điều này, mã này khá đơn giản.

Trong tệp, trong thư mục config/initializers, hãy thêm thông tin sau. Tôi tình cờ gọi tôi là fb_api_strategy.rb:

# authentication strategy to support API authentication over the webservice 
# via facebook 

require 'devise/strategies/database_authenticatable' 
require 'fb_graph' 
require 'warden' 

module Devise 
    module Strategies 
    class FbMobileDatabaseAuthenticatable < Authenticatable 
    def valid? 
    # if we have headers with the facebook access key 
    !!request.headers["fb_access_token"] 
    end 

    def authenticate! 
    token = request.headers["fb_access_token"] 
    fbuser = FbGraph::User.me(token) 
    fbuser = fbuser.fetch 

    user = User.find_for_facebook_mobile_client(fbuser.email) 

    # this either creates a new user for the valid FB account, or attaches 
    # this session to an existing user that has the same email as the FB account 

    if !!user && validate(user) { true } 
     user.after_database_authentication 
     success!(user) 
    elsif !halted? || !user 
     fail(:invalid) 
     end 
     end 
    end 
    end 
end 

Warden::Strategies.add(:fb_database_authenticatable, 
         Devise::Strategies::FbMobileDatabaseAuthenticatable) 

Trong config/initializers, thêm dòng sau vào devise.rb:

config.warden do |manager| 
    manager.default_strategies(:scope => :user).unshift :fb_database_authenticatable 
    end 

Để cho phép bạn hoặc tạo một người dùng hoặc tìm một người dùng hiện dựa trên email FB, thêm sau đây để mô hình người dùng của bạn:

def self.find_for_facebook_mobile_client(fb_email) 
    if user = User.where(:email => fb_email).first 
     user 
    else 
     User.create!(:email => fb_email, :password => Devise.friendly_token[0,20]) 
    end 
    end 

tôi không nghĩ fb_database_authenticatable là một cái tên chính xác, nhưng tôi sẽ rời khỏi đó như là một bài tập cho người đọc. Một bài tập khác là lưu trữ bộ nhớ đệm/lưu trữ mã thông báo truy cập FB và có thể tránh RT đến FB với mỗi cuộc gọi. Bạn nên lưu ý rằng mã thông báo truy cập từ ứng dụng dành cho thiết bị di động và ứng dụng đường ray sẽ khác nếu bạn thực hiện xác thực FB trên cả hai mặt, điều mà tôi cho rằng hầu hết mọi người sẽ muốn thực hiện. Điều này có thể ảnh hưởng đến sơ đồ bộ nhớ đệm của bạn.

Tôi nghĩ điều đó - vui mã hóa.

+2

Something cần lưu ý: Các quyền cơ bản cho việc sử dụng một tài khoản FB không cung cấp địa chỉ email. Bạn sẽ cần yêu cầu người dùng một cách rõ ràng về quyền này. – beeudoublez

+0

Điểm tốt @beeudoublez, đó chính xác là những gì tôi đã làm trong ứng dụng của mình. – Matt

0

Nếu bạn đang thiết tiêu đề yêu cầu trong xcode 4.3.2 bạn có thể sử dụng:

[request setValue:@"12345" forHTTPHeaderField:@"fbaccesstoken"]; 

nhưng bạn không thể sử dụng:

[request setValue:@"12345" forHTTPHeaderField:@"fb_access_token"]; // does NOT get set 
Các vấn đề liên quan