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



我正在使用RubyonRails构建一个Web应用程序和一个单独的API(这样用户就可以在需要时与他人共享他们收集的数据)。用户可以登录web应用程序并填写应发布到API服务器的数据。

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

您可以考虑API授权的看门人宝石。我考虑过它,但由于复杂性和缺乏用于我的用例的文档,所以决定不使用它。简单地说,我无法让它正常工作。

有一篇关于在没有设计的情况下使用管理员进行身份验证的好文章,它应该会让你对身份验证系统的活动部分有一个良好的感觉。Devise不适用于API身份验证,事实上,Devise最近删除了对API有用的一件事,即基于令牌的身份验证,显然API的身份验证不属于他们的路线图!

我使用上面引用的文章中的指导创建了我自己的仅JSON Warden策略,该策略使用OAUTH 2所有者密码凭据授予类型(请参阅RFC 6749)来生成和返回承载令牌,以用于未来的API请求。API客户端可以轻松创建JSON来进行这种身份验证,以获得授权访问令牌。

我将在下面提供一些Rails代码,让您开始使用,但您必须集成到您的特定环境中。无保修:)

典狱长初始值设定项:

# 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密码认证的管理员策略:

# 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访问令牌认证的管理员策略:

# 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):

# 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

当您说Web应用服务器和一个单独的API服务器时,每次Web应用服务器上有用户更新时,该服务器都需要相互通信。我所能建议的是,将它们分解为3个实体作为rails引擎。

  1. 核心:它将容纳您的所有模型和数据逻辑
  2. 应用程序:它将取决于您的核心引擎,并具有面向客户端的代码,主要是控制器和视图
  3. API:这将再次取决于你的核心引擎和处理逻辑,API控制器可能

为什么是Core?因为,当您需要更新业务逻辑时,只有一个地方:核心引擎。

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

  1. 从Collective Idea博客构建API-Rails Cast和构建Awesome Rails APIS
  2. 确保API的安全-RailsCast并寻找在RubyonRails中构建安全REST API的建议
  3. 我更喜欢OAuth来保护API调用。为了在rails中实现OAuth2,您可以使用doorkeeper

一旦完成了API的安全保护,就可以在Web应用程序中实现身份验证逻辑。您可以使用OAuth2从API验证您的应用程序。

此外,要使API仅对使用doorkeeper的OAuth调用可用,请执行以下操作:https://doorkeeper-provider.herokuapp.com/#client-应用

第页。S.:我更喜欢来自API的json响应,我认为这是一种首选趋势。)

EDIT-poster是一个chrome扩展,用于在实际为应用程序编写实验性/伪API之前制作这些API。它要快得多,因为你会知道在一天结束时你最终要设计什么。

通常是这样工作的。你的应用程序为每个用户发布一个秘密令牌(例如,它可以是md5哈希,它很长,而且非常随机)。令牌应由用户保管。您可以通过以下两条规则来做到这一点:-永远不要公开披露令牌(所有请求都应该从后端发出,没有AJAX调用等)-所有请求都应该通过https进行,因此它们是加密的

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

令牌应该作为参数传递,每个请求都要传递给API。

如果要构建json、基于xml的api,请使用rabl-gemhttps://github.com/nesquena/rabl.

对于更简单的身份验证,请选择基于会话的身份验证。该身份验证跟踪控制器中提供的会话变量。如果你想要整洁,为用户提供一些功能,那么就选择authological gemhttps://github.com/binarylogic/authlogic.

如果你想要完整的用户管理,那就去设计gem吧。

Rails使用会话来跟踪用户的状态,这些状态存储在用户的cookie中。

会话的文档可以在这里找到

如果你利用Devise这样的身份验证系统,你将可以访问控制器中的current_user方法,以及大量不同的助手,你可以利用这些助手,这取决于你的特定需求

相关内容

最新更新