This weekend I added OpenID to a Rails application for the first time, and this blog post describes the steps I took to integrate OpenID with Acts as Authenticated for account creation and access.
First I installed David's OpenID Rails plugin (as discussed at David's blog) into my application which was already using AAA to handle account creations and logins. I then created the following migration to add the OpenID identity URL to my user model:
class AddOpenId < ActiveRecord::Migration
def self.up
add_column :users, :identity_url, :string
end
def self.down
remove_column :users, :identity_url
end
end
And I changed the User model to allow accounts to be created either with login/email/password or with only an identity url (only changed lines are listed):
class User < ActiveRecord::Base
validates_presence_of :login,
:email, :if => :not_openid?
validates_length_of :login,
:within => 3..40, :if => :not_openid?
validates_length_of :email,
:within => 3..100, :if => :not_openid?
validates_uniqueness_of :login, :email, :salt, :allow_nil => true
def password_required?
not_openid? && (crypted_password.blank? or not password.blank?)
end
def not_openid?
identity_url.blank?
end
end
This allows me to create User records without the usual required fields as long as the user created the account via an OpenID login.
And finally, the controller changes:
class AccountController < ApplicationController
def login
if using_open_id?
open_id_authentication
elsif params[:login]
password_authentication(params[:login], params[:password])
end
end
protected def password_authentication(login, password) if self.current_user = User.authenticate(params[:login], params[:password]) successful_login else failed_login("Invalid login or password") end end def open_id_authentication authenticate_with_open_id do |result, identity_url| if result.successful? if self.current_user = User.find_or_create_by_identity_url(identity_url) successful_login else failed_login "Sorry, no user by that identity URL exists (#{identity_url})" end else failed_login result.message end end end
private def successful_login redirect_back_or_default(index_url) flash[:notice] = "Logged in successfully" end
def failed_login(message) redirect_to(:action => 'login') flash[:warning] = message end end
That's it! You can see it in action at the Rails plugin directory.
Update I updated this code to match the plugin changes that were made between the time I installed the plugin and the time I posted this entry. :) Update 2 I made another change to the code based on Geoff's comment. Thanks, Geoff!
Comments