登录Web App服务器的用户的API身份验证

 舍舍与你-6 发布于 2023-02-09 10:11

我正在构建一个Web应用程序和一个单独的API(以便用户可以使用Ruby on Rails与他人共享他们收集的数据).用户可以登录Web应用程序并填写应发布到API服务器的数据.

从我读过的所有内容到现在,我想我可以使用基于cookie的身份验证来检查用户是否登录到Web App.现在让我们假设用户想要将数据发布到API服务器.由于用户已通过Web App Server进行身份验证,因此应如何进行发布请求,以便API知道它正在从登录的特定用户获取数据.此外,如果用户想要从API获取数据,对他/她来说是私人的,应该如何为此目的提出请求?

3 个回答
  • 您可以考虑使用门卫宝石进行API授权.我考虑过它,但由于复杂性和我的用例缺乏文档而决定反对它.简单地说,我无法让它正常工作.

    有一篇关于使用warden而没有设计的认证的好文章应该让你对认证系统的移动部分有一个良好的感觉.Devise不适合API身份验证,事实上Devise最近删除了一个对基于令牌的身份验证的API有用的东西,显然API不是他们路线图的一部分!

    我使用上面引用的文章中的指南来创建我自己的仅JSON Warden策略,该策略使用OAUTH 2所有者密码凭据授权类型(请参阅RFC 6749)来生成并返回承载令牌,以便在将来的API请求中使用.API客户端可以轻松创建JSON以执行此类身份验证以获取授权访问令牌.

    我将提供一些Rails代码以帮助您从下面开始,但您必须集成到您的特定环境中.没有保修:)

    Warden初始化程序:

    # config/initializers/warden.rb
    Dir["./app/strategies/warden/*.rb"].each { |file| require file }
    
    Rails.application.config.middleware.insert_after ActionDispatch::ParamsParser, Warden::Manager do |manager|
      manager.default_strategies :null_auth, :oauth_access_token, :oauth_owner_password
      manager.failure_app = UnauthorizedController
    end
    

    OAUTH 2密码认证的Warden策略:

    # app/strategies/warden/oauth_owner_password_strategy.rb
    module Warden
      class OauthOwnerPasswordStrategy < Strategies::Base
        def valid?
          return false if request.get?
    
          params['grant_type'] == 'password' && params['client_id'] == 'web' && ! params['username'].blank?
        end
    
        def authenticate!
          user = User.with_login(params['username']).first
          if user.nil? || user.confirmed_at.nil? || ! user.authenticate!(params['password'])
            # delay failures for up to 20ms to thwart timing based attacks
            sleep(SecureRandom.random_number(20) / 1000.0)
            fail! :message => 'strategies.password.failed'
          else
            success! user, store: false
          end
    
          # ADD HERE: log IP and timestamp of all authentication attempts
        end
      end
    
      Strategies.add(:oauth_owner_password, OauthOwnerPasswordStrategy)
    end
    

    OAUTH 2访问令牌认证的Warden策略:

    # app/strategies/warden/oauth_access_token_strategy.rb
    module Warden
      class OauthAccessTokenStrategy < Strategies::Base
        def valid?
          # must be a bearer token
          return false unless auth_header = request.headers['authorization']
          auth_header.split(' ')[0] == 'Bearer'
        end
    
        def authenticate!
          # Use a periodic cleaner instead
          # clean out all old tokens. DOES NOT RUN CALLBACKS!
          Token.expired.delete
    
          # lookup bearer token
          token = Token.active.first(purpose: 'access', token: request.headers['authorization'].split(' ')[1])
          if token && (user = token.user) && user.confirmed_at
            success! user, store: false
          else
            # delay failures for up to 20ms to thwart timing based attacks
            sleep(SecureRandom.random_number(20) / 1000.0)
            fail! message: 'strategies.oauth_access_token.failed'
          end
        end
      end
    
      Strategies.add(:oauth_access_token, OauthAccessTokenStrategy)
    end
    

    空身份验证策略(在开发中很有用,只需config.null_auth_user在config/environments/development.rb中设置):

    # app/strategies/warden/null_auth_strategy.rb
    module Warden
      class NullAuthStrategy < Strategies::Base
        def valid?
          ! Rails.configuration.null_auth_user.blank?
        end
    
        def authenticate!
          user = User.with_login(params["username"]||Rails.configuration.null_auth_user).first
          if user.nil?
            fail! :message => "strategies.password.failed"
          else
            success! user, store: false
          end
        end
      end
    
      Strategies.add(:null_auth, NullAuthStrategy)
    end
    

    JSON客户端的Warden故障应用程序(使用裸机轨道控制器):

    # app/controllers/unauthorized_controller.rb
    class UnauthorizedController < ActionController::Metal
    
      def self.call(env)
        @respond ||= action(:respond)
        @respond.call(env)
      end
    
      def respond(env)
        self.status = 401
        self.content_type = 'json'
        self.response_body = { 'errors' => ['Authentication failure']}.to_json
      end
    end
    

    在基本API控制器中添加以下内容:

    before_filter :authenticate!
    
    protected
    
        helper_method :warden, :signed_in?, :current_user
    
        def warden
          request.env['warden']
        end
    
        def signed_in?
          !current_user.nil?
        end
    
        def current_user
          @current_user ||= warden.user
        end
    
        def authenticate!(*args)
          warden.authenticate!(*args)
          # ADD ANY POST AUTHENTICATION SETUP CODE HERE
        end
    

    会话控制器:

    class SessionsController < ApiController
      skip_before_filter :authenticate!
    
      # TODO exceptions and errors should return unauthorized HTTP response.
      # see RFC for details
    
      def create
        # mandate the password strategy.
        # don't use session store (don't want session cookies on APIs)
        authenticate!(scope: :oauth_owner_password, store: false)
    
        if signed_in?
          # create access token
          token = Token.create! purpose: 'access',
                                user: current_user,
                                expires_in: Rails.configuration.session_lifetime
    
           # Ensure response is never cached
           response.headers["Cache-Control"] = "no-store"
           response.headers["Pragma"] = "no-cache"
           response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
    
          # send the OAuth response
          render json: {
              access_token: token.token,
              token_type: 'Bearer',
              expires_in: token.expires_in,
              scope: 'user'
          }
        end
      end
    
      def destroy
        Token.current.delete
        warden.logout
        head :no_content
      end
    end
    

    您需要定义自己的用户和令牌模型以分别跟踪用户和承载令牌,令牌模型需要调用范围active以将结果集限制为未过期的令牌.令牌生成应该使用SecureRandom.urlsafe_base64

    2023-02-09 10:12 回答
  • 当您说Web应用服务器和单独的API服务器时,每当Web应用服务器上的用户发生更新时,它们都需要相互通信.我可以建议你将它们分解为3个实体作为rails引擎.

      核心:哪个将包含您的所有模型和数据逻辑.

      应用程序:这将取决于您的核心引擎并具有面向客户端的代码,主要是控制器和视图.

      API:这将再次依赖于您的核心引擎并具有处理逻辑,API控制器可能.

    为何选择Core?因为,当您需要更新业务逻辑时,它只是一个地方:核心引擎.

    现在,进一步回答您关于从Web应用服务器验证API调用的问题.你需要:

      从Collective Idea博客构建API - Rails Cast和构建令人敬畏的Rails APIS.

      保护API - Rails Cast并寻找在Ruby on Rails中构建安全REST API的建议.

      我更喜欢OAuth来保护API调用.要在rails中实现OAuth2,您可以使用门卫.

    完成API保护后,您可以在Web应用程序中实现身份验证逻辑.您可以使用OAuth2从API验证您的应用.

    此外,要使用门卫使您的API仅可用于OAuth呼叫:https://doorkeeper-provider.herokuapp.com/#client-applications

    PS:我更喜欢来自API的json响应,这是我所说的首选趋势.;)

    编辑- 邮递员是一款Chrome扩展进行实验性/假的API之前,你实际上是为你的应用程序写出来.它的速度要快得多,因为你知道在一天结束时你最终需要设计什么.

    2023-02-09 10:13 回答
  • 通常它的工作原理如下.您的应用为每个用户发出一个秘密令牌(例如,它可以是md5哈希,它很长,而且非常随机).令牌应该由用户保持安全.您可以通过以下两条规则来实现: - 永远不公开披露令牌(所有请求都应该来自后端,没有AJAX呼叫等) - 所有请求都应该通过https进行,因此它们是加密的

    使用令牌而不是用户名和密码的原因?如果令牌被泄露,您可以撤销它,用户仍然可以控制他们的帐户.此外,使用基于令牌的身份验证,不应该执行某些操作,例如更改与帐户关联的电子邮件或密码.

    令牌应作为参数传递给每个请求到您的API.

    2023-02-09 10:13 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有