登录到 Web App 服务器的用户的 API 身份验证 [英] API Authentication for user logged in to a Web App server

查看:19
本文介绍了登录到 Web App 服务器的用户的 API 身份验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am building a Web App and a separate API (so that users can share their collected data with someone if they want to) using Ruby on Rails. The users can log in on the web app and fill data that should be posted to the API Server.

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

From everything I have read till now, I guess that I can use cookie based authentication to check whether the user is logged in to the Web App. Now let's say that the user wants to post data to the API Server. Since the user is authenticated to the Web App Server, how should the post request be made so that the API knows that it is getting the data from the specific user who is logged in. Also if the user wants to get data from the API that is private to him/her, how should the get request be made for this purpose?

推荐答案

您可以考虑使用 doorkeeper gem 进行 API 授权.我考虑过它,但由于复杂性和我的用例缺乏文档而决定反对它.简而言之,我无法使其正常工作.

You could consider the doorkeeper gem for your API authorization. I considered it but decided against it because of complexity and lacking documentation for my use cases. Put simply I couldn't get it working properly.

有一篇很好的文章关于使用没有设计的监狱长应该让您对身份验证系统的活动部分有一个很好的感觉.Devise 不适用于 API 身份验证,事实上,Devise 最近删除了一项可能对 API 有用的东西,即基于令牌的身份验证,显然 API 不是他们路线图的一部分!

There is a good article on authentication using warden without devise which should give you a good feel for the moving parts of an authentication system. Devise is not appropriate for API authentication and in fact Devise recently removed the one thing that could be useful for API's which was token based authentication, obviously API's are not part of their roadmap!

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

I used the guidance in the article referenced above to create my own JSON only Warden strategy that uses an OAUTH 2 Owner Password Credentials Grant type (See RFC 6749) to generate and return a bearer token for use on future API requests. API clients can easily create the JSON to do this kind of authentication to obtain an authorization access token.

我将在下面提供一些 Rails 代码来帮助您入门,但您必须集成到您的特定环境中.不提供保修:)

I will provide some of the Rails code to get you started below, but you will have to integrate into your specific environment. No warranty offered :)

看守初始化器:

# 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 策略:

Warden strategy for OAUTH 2 password authentication:

# 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 策略:

Warden strategy for OAUTH 2 access token authentication:

# 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/environments/development.rb 中设置 config.null_auth_user):

Null authentication strategy (can be useful in development, just set config.null_auth_user within 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 故障应用程序(使用裸机 Rails 控制器):

Warden failure application for JSON clients (uses a bare metal rails controller):

# 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 控制器中添加以下内容:

Add the following in your base API controller:

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

您需要定义自己的 User 和 Token 模型来分别跟踪用户和不记名令牌,Token 模型需要有一个名为 active 的范围,以将结果集限制为未过期的令牌.令牌生成应使用 SecureRandom.urlsafe_base64

You will need to define your own User and Token models for tracking users and bearer tokens respectively, the Token model needs to have a scope called active to limit the result set to unexpired tokens. Token generation should use SecureRandom.urlsafe_base64

这篇关于登录到 Web App 服务器的用户的 API 身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆