Rails:从ActiveResource调用设计身份验证

tha*_*kal 2 ruby-on-rails devise ruby-on-rails-3

我的两个rails应用程序(app1,app2)正在使用活动资源进行通信.

app1调用app2在app2中创建一个用户.app2将创建用户,并希望app1然后将用户重定向到app2的经过身份验证的页面.

从app1到app2会不断要求用户登录.

我正在寻找一种方法来避免app2中的这个登录步骤,而是让用户在第一次活动资源调用期间登录以创建用户,并以某种方式获取写入的身份验证令牌.

使用Devise完成身份验证.Devise中是否有任何支持此功能的内容?

传递身份验证令牌的方式是什么?

yem*_*tin 7

您正在尝试实施单点登录服务(SSO)的形式(使用app1登录,并使用app2,app3自动进行身份验证...).遗憾的是,这不是一项微不足道的任务.你可以让它工作(也许你已经这样做了),但是为什么不集成一个现有的解决方案,而不是试图重新发明轮子呢?或者甚至更好,标准协议?这实际上相对容易.

CAS服务器

RubyCAS是一个Ruby服务器,它实现了耶鲁大学的CAS(中央认证服务)协议.我用它取得了很大的成功.

棘手的部分是让它与您现有的Devise身份验证数据库一起使用.我们遇到了同样的问题,经过一些代码潜水后,我想出了以下内容,这对我们来说就像是一种魅力.默认情况下,这将在您的RubyCAS服务器配置中进行/etc/rubycas-server/config.yml.当然,根据需要进行调整:

authenticator:
  class: CASServer::Authenticators::SQLEncrypted
  database:
    adapter: sqlite3
    database: /path/to/your/devise/production.sqlite3
  user_table: users
  username_column: email
  password_column: encrypted_password
  encrypt_function: 'require "bcrypt"; user.encrypted_password == ::BCrypt::Engine.hash_secret("#{@password}", ::BCrypt::Password.new(user.encrypted_password).salt)'

enter code here
Run Code Online (Sandbox Code Playgroud)

encrypt_function很痛苦......我不太高兴require在那里嵌入一​​个声明,但是嘿,它有效.不过,任何改进都会受到欢迎.

CAS客户

对于客户端(您希望集成到app2,app3中的模块......),RubyCAS-client gem 提供了一个Rails插件.

你需要一个初始化器rubycas_client.rb,例如:

require 'casclient'
require 'casclient/frameworks/rails/filter'

CASClient::Frameworks::Rails::Filter.configure(
  :cas_base_url  => "https://cas.example.com/"
)
Run Code Online (Sandbox Code Playgroud)

最后,您可以重新连接几个Devise调用以使用CAS,这样您的当前代码几乎可以正常工作:

# Mandatory authentication
def authenticate_user!
  CASClient::Frameworks::Rails::Filter.filter(self)
end

# Optional authentication (not in Devise)
def authenticate_user
  CASClient::Frameworks::Rails::GatewayFilter
end

def user_signed_in?
  session[:cas_user].present?
end
Run Code Online (Sandbox Code Playgroud)

不幸的是没有直接的替换方法current_user,但您可以尝试以下建议:

具有直接数据库访问权限的current_user

如果您的客户端应用程序可以访问后端用户数据库,则可以从那里加载用户数据:

def current_user
  return nil if session[:cas_user].nil?
  return User.find_by_email(session[:cas_user])
end
Run Code Online (Sandbox Code Playgroud)

但是对于更具可扩展性的架构,您可能希望将应用程序与后端分开.对于,您可以尝试以下两种方法.

current_user使用CAS extra_attributes

使用CAS协议提供的extra_attributes:基本上,将所有必要的用户数据作为extra_attributes传递给CAS令牌(添加一个extra_attributes键,列出所需的属性,在您的身份验证器中config.yml),并在客户端重建虚拟用户.代码看起来像这样:

def current_user
  return nil if session[:cas_user].nil?
  email = session[:cas_user]
  extra_attributes = session[:cas_extra_attributes]
  user = VirtualUser.new(:email => email,
    :name => extra_attributes[:name],
    :mojo => extra_attributes[:mojo],
  )
  return user
end
Run Code Online (Sandbox Code Playgroud)

VirtualUser类定义留作练习.提示:使用无表格的ActiveRecord(参见Railscast#193)应该让你编写一个可以与现有代码一样工作的替代品.

current_user在后端使用XML API和ActiveResource

另一种可能性是在用户后端准备XML API,然后使用ActiveResource检索用户模型.在这种情况下,假设您的XML API接受用于过滤用户列表的电子邮件参数,则代码如下所示:

def current_user
  return nil if session[:cas_user].nil?
  email = session[:cas_user]
  # Here User is an ActiveResource
  return User.all(:params => {:email => email}).first
end
Run Code Online (Sandbox Code Playgroud)

虽然这种方法需要额外的请求,但我们发现它是最灵活的.确保您的XML API安全,否则您可能会在系统中打开一个安全漏洞.SSL,HTTP身份验证,并且由于它仅供内部使用,因此请使用IP限制以获得良好的衡量标准.

额外奖励:其他框架也可以加入乐趣!

由于CAS是标准协议,因此您可以获得使用其他技术的应用程序使用单点登录服务的额外好处.有Java,PHP,.NetApache的官方客户端.

如果这有任何帮助,请告诉我,如果您有任何疑问,请随时询问.