Rails:从ActiveResource调用中设计身份验证 [英] Rails: Devise Authentication from an ActiveResource call

查看:73
本文介绍了Rails:从ActiveResource调用中设计身份验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



app1调用app2在app2中创建一个用户。 app2将创建该用户,并希望app1然后将用户重定向到app2的验证页面。



从app1到app2将始终要求用户登录。 >

我正在寻找一种方法来避免在app2中的登录步骤,而是使用户在第一次活动资源调用期间登录以创建用户,并以某种方式获取认证令牌。



使用Devise进行身份验证。有没有什么内置的Devise支持这个?



以认证令牌的方式传递?

解决方案

您正在尝试实施单点登录服务(SSO)的形式(使用app1登录,并通过app2,app3 ...自动验证)。不幸的是不是一件小事。你可能可以使它工作(也许你已经做到了),但是不是试图重塑轮子,而是为了整合现有的解决方案?或者更好的是,标准协议?这实际上比较容易。



CAS服务器



RubyCAS 是实现耶鲁大学CAS(中央认证服务)协议的Ruby服务器。我有很大的成功。



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

 认证者:
类:CASServer :: Authenticators :: SQLEncrypted
数据库:
适配器:sqlite3
数据库:/path/to/your/devise/production.sqlite3
user_table:users
username_column:电子邮件
password_column:encrypted_pa​​ssword
encrypt_function:'requirebcrypt; user.encrypted_pa​​ssword == :: BCrypt :: Engine.hash_secret(#{@ password},:: BCrypt :: Password.new(user.encrypted_pa​​ssword).salt)'

在此输入代码

encrypt_function 很难想出来。 ..我不太高兴在这里嵌入一个 require 语句,但嘿,它的工作原理。



CAS客户端



对于客户端(您所在的模块将要集成到app2,app3 ...)中,Rails插件由 RubyCAS客户端 gem。



您将需要一个初始化程序 ruby​​cas_client.rb ,类似于:

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

CASClient :: Frameworks :: Rails :: Filter.configure(
:cas_base_url =>https://cas.example.com/

最后,您可以重新连接几个Devise电话以使用CAS,以便您当前的代码将按原样工作:

 #强制身份验证
def authenticate_user!
CASClient :: Frameworks :: Rails :: Filter.filter(self)
end

#可选身份验证(不在Devise中)
def authenticate_user
CASClient :: Frameworks :: Rails :: GatewayFilter
end

def user_signed_in?
会话[:cas_user] .present?
end

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



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



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

  def current_user $ b $如果session [:cas_user] .nil? 
return User.find_by_email(session [:cas_user])
end

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



current_user使用CAS extra_attributes



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

  def current_user 
如果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

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]
#这里用户是一个ActiveResource
返回User.all(:params => {:email => email})首先
结束

虽然此方法需要额外的请求,我们发现它是最灵活的。只需确保您的XML API安全,或者您可能会在系统中打开一个缺陷安全漏洞。 SSL,HTTP身份验证,并且由于仅供内部使用,因此可以很好地衡量IP限制。



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



由于CAS是一种标准协议,您可以获得允许使用其他技术的应用程序使用单点登录服务的附加好处。有 Java 的官方客户, PHP 。Net Apache



让我知道这是否有任何帮助,并且不要犹豫,问你是否有任何问题。


My two rails applications(app1, app2) are communicating using active resource.

app1 calls app2 create a user inside app2. app2 would create the user and would like app1 then redirect the user to app2's authenticated pages.

going from app1 to app2 would invariably ask the user to log in.

I was looking for a way to avoid this login step in app2, instead make the user log in during the first active resource call to create user, and somehow get the authentication token written.

Authentication is done using Devise. Is there anything built into Devise that support this?

Is passing around the authentication token the way to go?

解决方案

You are trying to implement a form of Single Sign-On service (SSO) (sign in with app1, and be automatically authenticated with app2, app3...). It is unfortunately not a trivial task. You can probably make it work (maybe you already did), but instead of trying to reinvent the wheel, why not instead integrate an existing solution? Or even better, a standard protocol? It is actually relatively easy.

CAS server

RubyCAS is a Ruby server that implements Yale University's CAS (Central Authentication Service) protocol. I had great success with it.

The tricky part is getting it to work with your existing Devise authentication database. We faced the same problem, and after some code diving, I came up with the following, which works like a charm for us. This goes in your RubyCAS server config, by default /etc/rubycas-server/config.yml. Of course, adapt as necessary:

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

That encrypt_function was pain to figure out... I am not too happy about embedding a require statement in there, but hey, it works. Any improvement would be welcome though.

CAS client(s)

For the client side (module that you will want to integrate into app2, app3...), a Rails plugin is provided by the RubyCAS-client gem.

You will need an initializer rubycas_client.rb, something like:

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

CASClient::Frameworks::Rails::Filter.configure(
  :cas_base_url  => "https://cas.example.com/"
)

Finally, you can re-wire a few Devise calls to use CAS so your current code will work almost as-is:

# 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

Unfortunately there is no direct way to replace current_user, but you can try the suggestions below:

current_user with direct DB access

If your client apps have access to the backend users database, you could load the user data from there:

def current_user
  return nil if session[:cas_user].nil?
  return User.find_by_email(session[:cas_user])
end

But for a more extensible architecture, you may want to keep the apps separate from the backend. For the, you can try the following two methods.

current_user using CAS extra_attributes

Use the extra_attributes provided by the CAS protocol: basically, pass all the necessary user data as extra_attributes in the CAS token (add an extra_attributes key, listing the needed attributes, to your authenticator in config.yml), and rebuild a virtual user on the client side. The code would look something like this:

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

The VirtualUser class definition is left as an exercise. Hint: using a tableless ActiveRecord (see Railscast #193) should let you write a drop-in replacement that should just work as-is with your existing code.

current_user using an XML API on the backend and an ActiveResource

Another possibility is to prepare an XML API on the users backend, then use an ActiveResource to retrieve your User model. In that case, assuming your XML API accepts an email parameter to filter the users list, the code would look like:

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

While this method requires an extra request, we found it to be the most flexible. Just be sure to secure your XML API or you may be opening a gapping security hole in your system. SSL, HTTP authentication, and since it is for internal use only, throw in IP restrictions for good measure.

Bonus: other frameworks can join the fun too!

Since CAS is a standard protocol, you get the added benefit of allowing apps using other technologies to use your Single Sign-On service. There are official clients for Java, PHP, .Net and Apache.

Let me know if this was of any help, and don't hesitate to ask if you have any question.

这篇关于Rails:从ActiveResource调用中设计身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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