- 浏览: 2073201 次
- 性别:
- 来自: NYC
文章分类
- 全部博客 (628)
- Linux (53)
- RubyOnRails (294)
- HTML (8)
- 手册指南 (5)
- Mysql (14)
- PHP (3)
- Rails 汇总 (13)
- 读书 (22)
- plugin 插件介绍与应用 (12)
- Flex (2)
- Ruby技巧 (7)
- Gem包介绍 (1)
- javascript Jquery ext prototype (21)
- IT生活 (6)
- 小工具 (4)
- PHP 部署 drupal (1)
- javascript Jquery sort plugin 插件 (2)
- iphone siri ios (1)
- Ruby On Rails (106)
- 编程概念 (1)
- Unit Test (4)
- Ruby 1.9 (24)
- rake (1)
- Postgresql (6)
- ruby (5)
- respond_to? (1)
- method_missing (1)
- git (8)
- Rspec (1)
- ios (1)
- jquery (1)
- Sinatra (1)
最新评论
-
dadadada2x:
user模型里加上 protected def email ...
流行的权限管理 gem devise的定制 -
Sev7en_jun:
shrekting 写道var pattern = /^(0| ...
强悍的ip格式 正则表达式验证 -
jiasanshou:
好文章!!!
RPM包rpmbuild SPEC文件深度说明 -
寻得乐中乐:
link_to其实就是个a标签,使用css控制,添加一个参数: ...
Rails在link_to中加参数 -
aiafei0001:
完全看不懂,不知所然.能表达清楚一点?
"$ is not defined" 的问题怎么办
Allowing users to login with multiple authentication providers brings great benefits but also results in some annoying edge cases. For example, what happens when they login with one provider, logout and then login with another? What happens when they try to login with one having already logged in with another?
Typically authentication systems have a User model which handles most of the authentication logic but having multiple logins forces you to correctly separate the concepts of an Identity and a User. An Identity is a particular authentication method which a user has used to identify themselves with your site whilst a User manages data which is directly related to your site itself.
So to start you will want to create both User and Identity models. We will also add some convenience methods for creating identities and users when the OmniAuth callback is invoked:
So a user can have multiple identities and each identity belongs to a single user.
Next we need to handle logging in and logging out. This is managing session data since a logged in user is simply a person who has some session data confirming that they have been logged in. The OmniAuth callback which a provider will redirect to upon authenticating a user is /auth/:provider/callback so lets setup a route and a controller to handle this. We should also setup some helper methods on our Application Controller for handling the current user:
Now to login, all a user needs to do is go to /auth/provider and they will get redirected to Sessions Controller create method after authenticating. So there are a number of possibilities when they hit this action:
A user has never used your site before. They have no User model and no Identities either.
A user is logged out but they have logged into your site with a provider previously. They are now signing in with the same one again.
Just as above but they are now signing in with a different provider.
A user is logged in with a provider but they try to login with the same provider again.
A user is logged in but they try to login with a different provider.
The first two cases are just like a normal sign in process. The final 3 cases occur because we are allowing multiple providers and they can be tricky to handle.
Firstly, we need to grab authentication data given to us by the provider which is stored in request.env[omniauth.auth]. Then we need to check whether we have an identity which matches this data or create a new one.
How we proceed for here depends on whether the user is already logged in. If they aren't logged in then either they are a brand new user (so we treat their request like a registration) or they already have an account (so we treat this like a login request).
If they are logged in then we treat their request like they are trying to link an identity with their account. Either they are trying to link an identity which they have already linked (in which case we should display an error message telling them that) or it is a brand new identity so we go ahead and link it.
So at this point our skeleton create method looks like this:
So at this point, there are a couple of further considerations. Firstly on the signed in/identity not associated with user branch, there are two reasons why an identity might not be associated with a user. It could be that the identity is brand new, having never been used to sign in before. However, it could be that it has been used and so is already associated with a different user, although not necessarily a different person. Given that this user knew the login credentials for that identity, I think it is probably sufficiently prudent to assume that they are, in fact, the same person who also created the previous user. However, by simply reassigning the user to which the identity is associated with to the current one, you not only leave a user model potentially dangling with no identities to sign in with but also prevent the user from merging their data from their previous account in with this one. Resolving this will be dependent entirely on how much data, and the nature of that data, you have stored for each user but for sufficiently simple applications, you could at this point check to see if the old user has any identities left and, if not, delete that user. If the person using your site is likely to lose any data from this process then you would either need to make this sufficiently clear to them before proceeding or provide them with a way to migrate that data over (or handle it automatically, if possible).
Secondly, on the not signed in/no user model branch, you may need more registration data from your user than can be provided by your authentication providers. At this point, as I have assumed above, you can redirect them to a new user form and redirect them to this point if they try to access any other part of the app without completing it. Then create the user and log them in again when they have. Otherwise, if no further data is necessary or mandatory, you can go ahead and create a blank user model in the create method and log them straight in.
Finally, a few lose ends. Here is the destroy method for logging users out:
You'll also find that the OmniAuth callback url does not correctly verify the rails authenticity token and so will destroy any session data upon returning, thereby logging your current user out. This will prevent them from associating a new identity with their current account. You can get around this by adding skip_before_filter :verify_authenticity_token, only: :create to your sessions controller but I am unsure of the security implications of this.
You'll also need some migrations:
-
Typically authentication systems have a User model which handles most of the authentication logic but having multiple logins forces you to correctly separate the concepts of an Identity and a User. An Identity is a particular authentication method which a user has used to identify themselves with your site whilst a User manages data which is directly related to your site itself.
So to start you will want to create both User and Identity models. We will also add some convenience methods for creating identities and users when the OmniAuth callback is invoked:
# app/models/user.rb class User < ActiveRecord::Base has_many :identities def self.create_with_omniauth(info) create(name: info['name']) end end # app/models/identity.rb class Identity < ActiveRecord::Base belongs_to :user def self.find_with_omniauth(auth) find_by_provider_and_uid(auth['provider'], auth['uid']) end def self.create_with_omniauth(auth) create(uid: auth['uid'], provider: auth['provider']) end end
So a user can have multiple identities and each identity belongs to a single user.
Next we need to handle logging in and logging out. This is managing session data since a logged in user is simply a person who has some session data confirming that they have been logged in. The OmniAuth callback which a provider will redirect to upon authenticating a user is /auth/:provider/callback so lets setup a route and a controller to handle this. We should also setup some helper methods on our Application Controller for handling the current user:
# config/routes.rb YourAppName::Application.routes.draw do match '/auth/:provider/callback', to: 'sessions#create' match '/logout', to: 'sessions#destroy' end # app/controllers/sessions_controller.rb class SessionsController < ApplicationController def create # Login the User here end def destroy # Logout the User here end end # app/controllers/application_controller.rb class ApplicationController < ActionController::Base protect_from_forgery protected def current_user @current_user ||= User.find_by_id(session[:user_id]) end def signed_in? !!current_user end helper_method :current_user, :signed_in? def current_user=(user) @current_user = user session[:user_id] = user.nil? ? user : user.id end end
Now to login, all a user needs to do is go to /auth/provider and they will get redirected to Sessions Controller create method after authenticating. So there are a number of possibilities when they hit this action:
A user has never used your site before. They have no User model and no Identities either.
A user is logged out but they have logged into your site with a provider previously. They are now signing in with the same one again.
Just as above but they are now signing in with a different provider.
A user is logged in with a provider but they try to login with the same provider again.
A user is logged in but they try to login with a different provider.
The first two cases are just like a normal sign in process. The final 3 cases occur because we are allowing multiple providers and they can be tricky to handle.
Firstly, we need to grab authentication data given to us by the provider which is stored in request.env[omniauth.auth]. Then we need to check whether we have an identity which matches this data or create a new one.
How we proceed for here depends on whether the user is already logged in. If they aren't logged in then either they are a brand new user (so we treat their request like a registration) or they already have an account (so we treat this like a login request).
If they are logged in then we treat their request like they are trying to link an identity with their account. Either they are trying to link an identity which they have already linked (in which case we should display an error message telling them that) or it is a brand new identity so we go ahead and link it.
So at this point our skeleton create method looks like this:
def create auth = request.env['omniauth.auth'] # Find an identity here @identity = Identity.find_with_omniauth(auth) if @identity.nil? # If no identity was found, create a brand new one here @identity = Identity.create_with_omniauth(auth) end if signed_in? if @identity.user == current_user # User is signed in so they are trying to link an identity with their # account. But we found the identity and the user associated with it # is the current user. So the identity is already associated with # this user. So let's display an error message. redirect_to root_url, notice: "Already linked that account!" else # The identity is not associated with the current_user so lets # associate the identity @identity.user = current_user @identity.save() redirect_to root_url, notice: "Successfully linked that account!" end else if @identity.user.present? # The identity we found had a user associated with it so let's # just log them in here self.current_user = @identity.user redirect_to root_url, notice: "Signed in!" else # No user associated with the identity so we need to create a new one redirect_to new_user_url, notice: "Please finish registering" end end end
So at this point, there are a couple of further considerations. Firstly on the signed in/identity not associated with user branch, there are two reasons why an identity might not be associated with a user. It could be that the identity is brand new, having never been used to sign in before. However, it could be that it has been used and so is already associated with a different user, although not necessarily a different person. Given that this user knew the login credentials for that identity, I think it is probably sufficiently prudent to assume that they are, in fact, the same person who also created the previous user. However, by simply reassigning the user to which the identity is associated with to the current one, you not only leave a user model potentially dangling with no identities to sign in with but also prevent the user from merging their data from their previous account in with this one. Resolving this will be dependent entirely on how much data, and the nature of that data, you have stored for each user but for sufficiently simple applications, you could at this point check to see if the old user has any identities left and, if not, delete that user. If the person using your site is likely to lose any data from this process then you would either need to make this sufficiently clear to them before proceeding or provide them with a way to migrate that data over (or handle it automatically, if possible).
Secondly, on the not signed in/no user model branch, you may need more registration data from your user than can be provided by your authentication providers. At this point, as I have assumed above, you can redirect them to a new user form and redirect them to this point if they try to access any other part of the app without completing it. Then create the user and log them in again when they have. Otherwise, if no further data is necessary or mandatory, you can go ahead and create a blank user model in the create method and log them straight in.
Finally, a few lose ends. Here is the destroy method for logging users out:
def destroy self.current_user = nil redirect_to root_url, notice: "Signed out!" end
You'll also find that the OmniAuth callback url does not correctly verify the rails authenticity token and so will destroy any session data upon returning, thereby logging your current user out. This will prevent them from associating a new identity with their current account. You can get around this by adding skip_before_filter :verify_authenticity_token, only: :create to your sessions controller but I am unsure of the security implications of this.
You'll also need some migrations:
class CreateUsers < ActiveRecord::Migration def change create_table :users end end class CreateIdentities < ActiveRecord::Migration def change create_table :identities do |t| t.string :uid t.string :provider t.references :user end add_index :identities, :user_id end end
-
发表评论
-
brew service restart
2013-07-06 22:56 1446brew services restart memcached ... -
git如何合并 多个commit
2013-07-02 20:42 9369需要先搞明白rebase 然后,进这个界面 pick b ... -
rvm create gemset
2013-07-01 09:00 1280rvm ruby-1.9.3-p429 do rvm gems ... -
关于devise结合github通过omniauth登录
2013-06-24 04:47 4156最近写了个github帐户登录Demo: https://gi ... -
cdata 和 xml xmlParseEntityRef: no name 错误
2013-05-04 00:24 5000Problem: An XML parser returns ... -
一目了然 rails html xml encode decode
2013-05-03 23:37 31171.9.2p320 :001 > require ' ... -
使用scope 链接多个where条件
2013-05-02 09:17 2606scope :by_category, (lamb ... -
在rspec里使用 route path
2013-05-01 20:09 1008Rspec.configure do |config| ... -
select_tag default value & options
2013-04-10 21:40 2189#If you are using select_tag ... -
Jquery array remove
2013-04-10 21:38 4535Array.prototype.remove = fu ... -
ruby readline的两种写法
2013-04-09 10:21 901f = File.read('public/file.cs ... -
关于encoding utf-8
2013-04-04 20:55 4087一 gem解决方案 https://github.com/m- ... -
我见过最清楚的解释class_eval 和 instance_eval
2013-04-02 07:06 3326忘了,看一次就能回忆起来 class A # def ... -
oauth github和multiple oauth
2013-04-01 11:08 1544http://railscasts.com/episodes/ ... -
Ruby Jquery 地图,地理信息相关资源
2013-03-22 20:32 935Railscast Geocorder Geocorde ... -
load migrate file and load
2013-03-22 05:52 996Dir[Rails.root.join('db','mig ... -
Brew update problem
2013-03-22 05:48 1340引用 MBA:~ fortin$ brew update er ... -
Jquery sort table number
2013-03-19 01:01 1140So here is what the column is s ... -
update_all
2013-03-13 02:09 1340Article.limit(2).update_all [&q ... -
接着上面的母子表单
2013-03-12 11:45 869Creating a new Rails proj ...
相关推荐
**Python-django-oauth2-provider** 是一个用于 Django 框架的开源库,它使得开发者能够轻松地在自己的 Django 应用中实现 OAuth2 认证和授权机制。OAuth2 是一种广泛使用的开放标准,允许第三方应用在用户授权的...
apache-oltu-oauth2-provider-demo, Apache Oltu提供程序服务器演示( Oauth 2.0 ) apache-oltu-oauth2-provider-demoApache Oltu提供程序服务器演示( Oauth 2.0 )对于基本OAuth2流程,请阅读以下内容: ...
使用Apple ID Provider登录OAuth 2.0客户端 该软件包为PHP League的提供了Apple ID OAuth 2.0支持。 在你开始之前 您可以在这里找到Apple的官方文档: : 如果您要求提供电子邮件地址或名称,请注意,只有在您首次...
node-oauth2-provider, 一个简单的可以定制 OAuth 2.0提供程序( 服务器) 用于 node.js 用于连接 & Express的OAuth 2提供商这是用于实现支持服务器端( 代码) 和客户端( 令牌) OAuth流的OAuth2服务器( 提供者)的node....
Spring Security OAuth 是一个用于保护RESTful Web服务的框架,它为OAuth 1.0a和OAuth 2.0协议提供了全面的支持。在这个源码中,我们可能会看到如何将Spring Security与OAuth结合,以构建安全的Web应用程序和服务。...
在本文中,我们将深入探讨如何使用Apache JMeter进行OAuth 1.0授权认证。OAuth 1.0是一种授权协议,允许第三方应用安全地访问用户在另一服务上的资源,而无需获得用户的用户名和密码。JMeter是一款强大的性能测试...
Apache Shiro是一个强大的Java安全框架,它提供了身份验证、授权、会话管理和加密等功能,而OAuth2则是一种开放标准,用于授权第三方应用访问用户资源。将Shiro与OAuth2集成,可以实现更灵活的安全控制,特别是在...
OAuth 2.0 是一种广泛使用的授权框架,它允许第三方应用在用户许可的情况下访问其私有资源。在本文中,我们将深入探讨 OAuth 2.0 的核心概念,并结合 Java 实现来理解其工作原理。 OAuth 2.0 主要分为四个角色:...
使用 spring 安全性的示例 OAuth 提供程序请参见 构建和运行测试:gradle clean build integrationTest 运行: gradle tomcatRun 注册新用户: curl -X POST -H "内容类型:应用程序/json" -H "授权:基本 ...
OAuth 2.0 是一种广泛使用的开放网络标准,旨在解决应用程序获取用户授权访问特定资源时的安全问题。在本文中,作者阮一峰详细解释了OAuth 2.0 的设计思路和工作流程,以便读者能够更好地理解和应用这一授权框架。 ...
**OAuth2.0协议概述** OAuth2.0是一种授权框架,允许第三方应用在用户许可的情况下,访问特定资源。它主要用于安全地实现用户数据的共享,比如社交媒体登录、云存储服务等。OAuth2.0的核心是将用户的授权过程与实际...
OAuth2是OAuth协议的最新版本,它解决了OAuth1的一些复杂性和安全性问题。在这个"oauth核心jar包"中,包含了OAuth2框架的关键组件,用于构建客户端和服务端的应用。 首先,`oauth2.resourceserver`这个标签可能指的...
Spring Security OAuth2 Provider 是一个强大的安全框架,用于构建安全的Web应用和服务。在这个主题中,我们将探讨如何使用Spring Security作为OAuth2提供者,实现第三方登录的简单演示。OAuth2是一种授权框架,允许...
$provider = new OAuth2\Provider\Google([ 'clientId' => 'your_client_id', 'clientSecret' => 'your_client_secret', 'redirectUri' => 'http://yourapp.com/callback', ]); if (!isset($_GET['code'])) { /...
OAuth让应用开发者可以在不获取用户密码的情况下,为用户提供一种安全的方式去授权第三方应用访问他们的资源。在PHP中实现OAuth,我们可以使用一些现有的库,例如这个例子中的"php-oauth"。 在PHP中实现OAuth,我们...
.provider(OAuthService.class) .apiKey(consumerKey) .apiSecret(consumerSecret) .build(); ``` 3. **获取请求令牌**: 用户授权前,客户端需要获取一个临时的请求令牌,以便引导用户到授权页面。 ```java ...
OAuth Signpost是一个专门为Java开发者设计的开源库,它简化了OAuth协议的实现,使得开发者能够更轻松地在自己的应用程序中集成OAuth授权功能。OAuth是一种开放标准,主要用于安全地授权第三方应用访问用户存储在另...
OAuth 2.0 是一种广泛使用的开放网络授权协议,它允许第三方应用安全地访问用户存储在其他服务上的数据,而无需获取用户的登录凭据。这个压缩包文件包含的是 OAuth 2.0 的服务端和客户端的源代码,这对于理解OAuth ...
3. **服务提供商(Service Provider)**:提供资源和服务的实体,也称为资源服务器(Resource Server)。 4. **访问令牌(Access Token)**:用于访问资源的一种凭据,由服务提供商颁发给客户端。 5. **请求令牌...