我很难理解并正确实施用户身份验证在API中。换句话说,我很难理解Grape API与前端框架(如Backbone.js,AngularJS或Ember.js)的集成。葡萄和设计的用户身份验证
我试图摆动所有不同的方法,并阅读了很多关于这个,但谷歌回报我真正不好的资源,在我看来,就像没有真正好的文章在这个主题上 - Rails和用户身份验证与设计和前端框架。
我会描述我目前的关键点,希望你能为我的实施提供一些反馈意见,也许可以让我指出正确的方向。
当前实现
我有后台Rails的REST API具有以下的Gemfile(我会故意缩短所有文件代码)
gem 'rails', '4.1.6'
gem 'mongoid', '~> 4.0.0'
gem 'devise'
gem 'grape'
gem 'rack-cors', :require => 'rack/cors'
我目前的实施只有使用API以下路线(routes.rb):
api_base /api API::Base
GET /:version/posts(.:format)
GET /:version/posts/:id(.:format)
POST /:version/posts(.:format)
DELETE /:version/posts/:id(.:format)
POST /:version/users/authenticate(.:format)
POST /:version/users/register(.:format)
DELETE /:version/users/logout(.:format)
我创建具有以下模型user.rb
class User
include Mongoid::Document
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
field :email, type: String, default: ""
field :encrypted_password, type: String, default: ""
field :authentication_token, type: String
before_save :ensure_authentication_token!
def ensure_authentication_token!
self.authentication_token ||= generate_authentication_token
end
private
def generate_authentication_token
loop do
token = Devise.friendly_token
break token unless User.where(authentication_token: token).first
end
end
end
以我控制器我创建下面的文件夹结构:controllers-> API-> V1和我有创建以下共享模块身份验证(authentication.rb)
module API
module V1
module Authentication
extend ActiveSupport::Concern
included do
before do
error!("401 Unauthorized", 401) unless authenticated?
end
helpers do
def warden
env['warden']
end
def authenticated?
return true if warden.authenticated?
params[:access_token] && @user = User.find_by(authentication_token: params[:access_token])
end
def current_user
warden.user || @user
end
end
end
end
end
end
所以每次当我想确保,我的资源将与认证令牌被调用,我可以简单地通过调用补充一点:include API::V1::Authentication
的葡萄资源:
module API
module V1
class Posts < Grape::API
include API::V1::Defaults
include API::V1::Authentication
现在我有另一个葡萄资源称为Users(users.rb),在这里我实现了用于认证,注册和注销的方法(我认为我在这里将苹果与梨混合在一起,并且我应该将登录/注销过程提取到另一个Grape资源 - 会话中)。
module API
module V1
class Users < Grape::API
include API::V1::Defaults
resources :users do
desc "Authenticate user and return user object, access token"
params do
requires :email, :type => String, :desc => "User email"
requires :password, :type => String, :desc => "User password"
end
post 'authenticate' do
email = params[:email]
password = params[:password]
if email.nil? or password.nil?
error!({:error_code => 404, :error_message => "Invalid email or password."}, 401)
return
end
user = User.find_by(email: email.downcase)
if user.nil?
error!({:error_code => 404, :error_message => "Invalid email or password."}, 401)
return
end
if !user.valid_password?(password)
error!({:error_code => 404, :error_message => "Invalid email or password."}, 401)
return
else
user.ensure_authentication_token!
user.save
status(201){status: 'ok', token: user.authentication_token }
end
end
desc "Register user and return user object, access token"
params do
requires :first_name, :type => String, :desc => "First Name"
requires :last_name, :type => String, :desc => "Last Name"
requires :email, :type => String, :desc => "Email"
requires :password, :type => String, :desc => "Password"
end
post 'register' do
user = User.new(
first_name: params[:first_name],
last_name: params[:last_name],
password: params[:password],
email: params[:email]
)
if user.valid?
user.save
return user
else
error!({:error_code => 404, :error_message => "Invalid email or password."}, 401)
end
end
desc "Logout user and return user object, access token"
params do
requires :token, :type => String, :desc => "Authenticaiton Token"
end
delete 'logout' do
user = User.find_by(authentication_token: params[:token])
if !user.nil?
user.remove_authentication_token!
status(200)
{
status: 'ok',
token: user.authentication_token
}
else
error!({:error_code => 404, :error_message => "Invalid token."}, 401)
end
end
end
end
end
end
我意识到,我在这里一吨的代码,它可能没有什么意义,但是这是我现在有,我能够使用authentication_token
针对我的API调用它们由模块保护Authentication
。
我觉得这个解决方案不好,但我真的很想找到更简单的方法来通过API实现用户身份验证。我有几个问题,我列在下面。
问题
- 你觉得这种实现是很危险的,如果是的话,为什么呢? - 我认为这是因为使用了一个令牌。有没有办法改善这种模式?我也看到了具有到期时间等的单独模型
Token
的实现。但我认为这几乎就像重新发明轮子,因为为此我可以实现OAuth2。我想有更轻的解决方案。 - 为身份验证创建新模块并将其仅包含到需要它的资源中是一种很好的做法?
- 你知道关于这个主题的任何好教程 - 实现 Rails + Devise + Grape吗?另外,你是否知道开源的Rails项目有哪些好的 ?
- 我该如何使用更安全的不同方法来实现它?
我很抱歉这么长的帖子,但我希望更多的人有同样的问题,这可能会帮助我找到更多的答案在我的问题。
真的,没有人在做同样的事情?或者其阅读时间太长?我的天啊.... – 2014-10-29 18:01:20