【问题标题】:Using authlogic_api for Rails REST API access使用 authlogic_api 访问 Rails REST API
【发布时间】:2010-06-24 16:25:59
【问题描述】:

我正在为仅通过 REST 调用访问的 Steam 游戏编写 Rails 后端 API,因此不需要用户特定的身份验证。我正在尝试为 Authlogic gem 实现authlogic_api plug-in,它使用 api_key/signature 机制来限制访问。我已经实现了 rdocs 中概述的 ApplicationSessionApplicationAccount 模型,但我不确定如何修改我的 ApplicationController 以限制访问。

查看源代码,authlogic_api 插件似乎修改了来自 Authlogic 的 ActsAsAuthenticSession 模块。但由于这本质上是“单一访问”身份验证,需要在每个请求上传递 API 密钥和签名,所以我看不出会话将如何成为一个因素。

有没有人在他们的应用程序中成功实现了 authlogic_api?如果是这样,您会分享您设置 ApplicationController 的方法吗?

【问题讨论】:

    标签: ruby-on-rails ruby security rest authlogic


    【解决方案1】:

    实际上,它要简单得多。使用 Authlogic 示例中的所有代码有点矫枉过正 - 它主要管理存储会话详细信息,您不需要为应用程序(也称为客户端)会话执行此操作。每次请求都会重新确认客户端会话。

    你只需要:

    models\client.rb

    class Client < ActiveRecord::Base
      acts_as_authentic do |config|
      end
    end
    

    models\client_session.rb

    class ClientSession < Authlogic::Session::Base
      api_key_param 'app_key'
    end
    

    控制器\application_controller

    before_filter :verify_client
    
    def verify_client
      @client_session = ClientSession.new()
      unless @client_session.save # if client session not successfully created using the api_key and signature, render an error and block the request
        @error = {:description => "Couldn't validate client application."}
        render :template => 'errors/error.xml.builder'
      end
    end
    

    您还需要运行迁移来创建客户端表。并非以下所有字段都是必需的,但它们不会受到影响。

    class CreateClients < ActiveRecord::Migration
      def self.up
        create_table :clients do |t|
          # human fields
          t.string :name
          t.string :owner
          t.string :owner_email
          t.string :owner_phone
          # login fields
          t.string :api_key, :null => false
          t.string :api_secret, :null => false
          t.string :password_salt
          t.string :persistence_token
          t.string :perishable_token
          # automagical fields (courtesy of authlogic & authlogic_api)
          t.integer :failed_login_count
          t.datetime :last_request_at
          t.integer :request_count
          t.string :last_request_ip
          # automagical fields (courtesy of rails)
          t.timestamps
        end
      end
    
      def self.down
        drop_table :clients
      end
    end
    

    【讨论】:

      【解决方案2】:

      您可能不需要 Authlogic 的开销。

      如果您正在生成客户端将发送的 URL,只需添加过期时间戳,并对整个 URL 执行 MD5 哈希(签名),将结果添加为最终查询参数。

      请在控制器操作上使用 before_filter,即将验证 URL 的 signed_url 方法。此方法应从请求对象中获取 URL。验证过期没有过去。从 URL 中删除签名以将其放置在与生成原始 URL 相同的格式中,执行此操作并验证匹配。瞧。

      过期对于确保以后不能重复使用 URL 很重要。

      这是一种很好的集中方式,可以作为无需登录即可授权请求的替代方式。只要您生成了 URL,它将在任何主机到期之前一直有效。

      【讨论】:

      • 感谢您的回复。但是,我不明白这将如何验证传入请求来自有效客户端? api 密钥/签名机制至少需要客户端提供这些凭据。
      【解决方案3】:

      通过遵循Authlogic example 解决了这个问题,只需用 ClientAccount 模型替换 User 模型。所以在我的应用程序控制器中,我有:

      before_filter :require_client
      
      def require_client
        unless current_client
          store_location
          render :text => 'Authentication failed', :status => 401
          return false
        end
      end
      
      def require_no_client
        if current_client
          store_location
          render :text => 'Client session already exists', :status => 401
          return false
        end
      end
      
      def current_client_session
        return @current_client_session if defined?(@current_client_session)
        @current_client_session = ClientSession.find
      end
      
      def current_client
        return @current_client if defined?(@current_client)
        @current_client = current_client_session && current_client_session.record
      end
      

      ClientAccount 模型acts_as_authentic,ClientSession 模型为Authlogic(authenticate_with ClientAccount)处理创建和销毁会话:

      class ClientSessionsController < ApplicationController
        before_filter :require_no_client, :only => [:new, :create]
        before_filter :require_client, :only => :destroy
      
        def new
          @client_session = ClientSession.new
        end
      
        def create
          @client_session = ClientSession.new(params[:client_session])
          if @client_session.save
            redirect_back_or_default account_url
          else
            render :action => :new
          end
        end
      
        def destroy
          current_client_session.destroy
          redirect_back_or_default new_client_session_url
        end
      end
      

      此解决方案运行良好,因为我们能够为不同的客户端生成不同的 API 密钥/签名组合,从而为我们提供额外的使用数据。唯一的“问题”是如果您正在执行诸如分段文件上传之类的操作,因为 POST 哈希使用原始 POST 数据。

      【讨论】:

        猜你喜欢
        • 2019-05-17
        • 1970-01-01
        • 2013-12-29
        • 1970-01-01
        • 2020-07-30
        • 2012-10-20
        • 2015-06-01
        • 2019-10-24
        • 2017-11-08
        相关资源
        最近更新 更多