Forum: Ruby on Rails User Authentication

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
C143acf82f94860ef6e2cba52b2de831?d=identicon&s=25 Greg MacGregor (Guest)
on 2006-03-02 05:37
(Received via mailing list)
I'm trying to create a simple authentication system but am failing
miserably. I'm (sort of) following the "Logging In" chapter of the Agile
book. Ideally, any access to http://example.com/publish (and any of its
subdirectories) should redirect to http:/example.com/publish/login when
there is no valid session user_id.

Code so far:

--------------------------------------------

# controller
class PublishController < ApplicationController

  before_filter :authenticate, :except => [:login, :login_user]

  def login
    if request.post?
      logged_in_user = @user.attempt_login
        if logged_in_user
          session[:user_id] = logged_in_user.id
          redirect_to(:action => 'index')
        else
          flash[:notice] = 'Invalid username or password. Please try
again'

        end
    end
  end

  def self.authenticate
    unless session[:user_id]
      redirect_to :action => 'login'
    end
  end

end

#model
class User < ActiveRecord::Base

  require "digest/sha1"

  attr_accessor :password
  attr_accessible :username, :password, :first_name, :last_name, :email

  validates_uniqueness_of :username
  validates_presence_of :username, :first_name, :last_name, :email
  validates_length_of :password, :within => 5..40, :on => :create

  def before_create
    self.sha_password = User.encrypt(self.password)
  end

  def after_create
    @password = nil
  end

  private
  def self.encrypt(password)
    Digest::SHA1.hexdigest(password)
  end

  def self.login_user(username, password)
    encrypted_password = encrypt(password || "")
    find(:first, :conditions => ["username = ? and sha_password = ?",
username, encrypted_password])
  end

  def attempt_login
    User.login_user(self.username, self.password)
  end

end

--------------------------------------------

If I browse to, say, http://example.com/publish/user/list I get a
NoMethodError in Publish#user:

undefined method `authenticate' for #<PublishController:0x387ab58>W

When I browse to http://example.com/publish/login/ I see the login form
but
upon submit I get another NoMethodError in Publish#login:

You have a nil object when you didn't expect it!
The error occured while evaluating nil.attempt_login


I'm totally stumped and appreciate any help.

Greg
602f73f02a8b8abcf01ca093e1762006?d=identicon&s=25 Micah Bly (yak)
on 2006-03-02 06:08
Greg MacGregor wrote:
> I'm trying to create a simple authentication system but am failing
> miserably. I'm (sort of) following the "Logging In" chapter of the Agile
> book. Ideally, any access to http://example.com/publish (and any of its
> subdirectories) should redirect to http:/example.com/publish/login when
> there is no valid session user_id.

Greg MacGregor wrote:
> I'm trying to create a simple authentication system but am failing
> miserably. I'm (sort of) following the "Logging In" chapter of the Agile
> book. Ideally, any access to http://example.com/publish (and any of its
> subdirectories) should redirect to http:/example.com/publish/login when
> there is no valid session user_id.

Are you sure you don't want to save a lot of time and use one of the
pre-written packages that are available? Salted, for example:

http://wiki.rubyonrails.com/rails/pages/SaltedHash...

I am a fellow Rails newbie, and I had no problem getting Salted up and
running. And it's really easy to modify.  You might also want to look
here, for user *authorization*:

http://d-haven.org/modules/news/article.php?storyid=28

I haven't tried that yet, but I'm going to set it up tomorrow, and I'm
thinking it will be up and running in 1-2 hours.

One of the reasons Rails is so awesome is that there is SO much existing
code out there to use. And it's so easy to modify to do exactly what you
want to do.

BUT... if you do want to write your own User system, I'm sure there's a
lot of folks here who can help you.  You wouldn't want to be taking
Rails or Ruby coding advice from me just yet...

Micah
C143acf82f94860ef6e2cba52b2de831?d=identicon&s=25 Greg (Guest)
on 2006-03-02 06:12
Micah Bly wrote:

> Are you sure you don't want to save a lot of time and use one of the
> pre-written packages that are available?

... building it myself (and running into errors such as this) will help
me to better understand how the controller and model interact with one
another. I appreciate the links, Micah!

Greg
38a8230ed3d5c685558b4f0aad3fc74b?d=identicon&s=25 Joe Van Dyk (Guest)
on 2006-03-02 06:21
(Received via mailing list)
On 3/1/06, Greg MacGregor <gmacgregor@gmail.com> wrote:
>
>           redirect_to(:action => 'index')
>         else
>           flash[:notice] = 'Invalid username or password. Please try again'
>         end
>     end
>   end
>
>   def self.authenticate

This needs to be a regular method (what's the correct terminology
here?), not a class method.
 You want:

      def authenticate

And I'd put the authenticate method in the Application controller,
that way other controllers can access it (note: if you do that, you'll
need to change the below redirect to also include the controller.

Joe
27c170f482104299af279902be0a9c26?d=identicon&s=25 Trevor Squires (Guest)
on 2006-03-02 06:39
(Received via mailing list)
Hi Greg,

comments inline:

On 1-Mar-06, at 8:37 PM, Greg MacGregor wrote:

>
> I'm trying to create a simple authentication system but am failing
> miserably. I'm (sort of) following the "Logging In" chapter of the
> Agile book. Ideally, any access to http://example.com/publish (and
> any of its subdirectories) should redirect to http:/example.com/
> publish/login when there is no valid session user_id.
>

Okay, it's the "sort of" that's biting you in the rear right now.
I'll point out why you're getting the errors but I advise you to go
back and work through the Logging In chapter again, step by step.

more below:

>     if request.post?
>
One of your errors is that you're trying to call (effectively)
"nil.attempt_login".  The offending line is above, where you call
@user.attempt_login.  The problem is, you're not assigning a value to
@user so it's 'nil'.

If I look at your User model below, I'd guess you really want to say:

logged_in_user = User.login_user(params[:username], params[:password])

of course, this assumes you're actually passing username and password
as POST params.


>   def self.authenticate
>     unless session[:user_id]
>       redirect_to :action => 'login'
>     end
>   end
>

The authenticate method above has "self." in front of it which makes
it a *class* method.  i.e. you can only call it as
PublishController.authenticate

However, your filters are expected to be *instance* methods of the
controller so ditch the 'self.' and that will eliminate your
"undefined method  `authenticate`" error.

HTH,
Trevor
--
Trevor Squires
http://somethinglearned.com
C143acf82f94860ef6e2cba52b2de831?d=identicon&s=25 Greg (Guest)
on 2006-03-02 06:53
Thanks Trevor. Before you posted I made these changes:

class PublishController < ApplicationController

  before_filter :authenticate

  def login
    if request.post?
      @user = User.new(params[:user])
      logged_in_user = @user.attempt_login
        if logged_in_user
          session[:user_id] = logged_in_user.id
          redirect_to(:controller => '/publish/user', :action => 'list')
        else
          flash[:notice] = 'Invalid username or password. Please try
again'
        end
    end
  end

  def authenticate
    unless session[:user_id]
      redirect_to :action => 'login'
    end
  end

end


----

and i added this to my model:

  public
  def attempt_login
    User.login_user(self.username, self.password)
  end

(note public)

everything seems to work now but I have another problem. After
successful login I want to point the user to
example.com/publish/user/list. I've referred to this as

redirect_to(:controller => '/publish/user', :action => 'list')

above. My app looks like

app
 +controllers
    -application_controller.rb
    -publish_controller.rb
    +publish
       -user_controller.rb

There is indeed a list action in the user controller, so how come the
redirect doesn't work?

Thanks again for the help.

Greg
38a8230ed3d5c685558b4f0aad3fc74b?d=identicon&s=25 Joe Van Dyk (Guest)
on 2006-03-02 06:58
(Received via mailing list)
On 3/1/06, Greg <gmacgregor@gmail.com> wrote:
>         if logged_in_user
>     unless session[:user_id]
>
>
>
> There is indeed a list action in the user controller, so how come the
> redirect doesn't work?
>
> Thanks again for the help.
>
> Greg

Is the User controller defined like:
  class Publish::AdminController < ApplicationController
?

What exactly doesn't work with the redirection?
F2d3287043f963f539d90d5d1ed25c5b?d=identicon&s=25 Chris Jennings (cpher)
on 2006-03-02 15:16
Greg,
Like you, when I first started with Rails I used the authentication
sample from the Agile book. But I quickly dicovered that it was too
limited, even for the hobby site I was building.

I recommend looking at the acts_as_authenticated plugin. It's easy to
set up, and has convenience methods for handy things like displaying the
name of the user logged on (e.g. current_user.login). Or, "logged_in?",
a simple test to determine if someone is logged in. This is handy if you
want to display special menus to users who are logged in vs. the general
public. Of course, that just scratches the surface. It also integrates
ActionMailer for emailing, etc.

Of course, you're free to code this stuff yourself, but I decided that
using an available plugin for the drudgery of authentication left me
with more time for writing my "actual" application.

FYI, There's even a separate, new ACL system written to complement the
acts_as_authenticated plugin (I haven't tried it yet). So you can assign
roles/permissions to certain users.

Good luck!
-Chris
C143acf82f94860ef6e2cba52b2de831?d=identicon&s=25 Greg (Guest)
on 2006-03-02 16:09
Joe Van Dyk wrote:
> Is the User controller defined like:
>   class Publish::AdminController < ApplicationController
> ?
>
> What exactly doesn't work with the redirection?

Given my structure above, the User controller is defined like this:
class Publish::UserController < ActionController ... or

-app
   +controllers
     -publish_controller.rb
     +publish
        -user_controller.rb

Like I said, there is a list action in the user_controller that I know
works. After login I am redirected to:
http://example.com/publish/user/list and get the error: "no action for
user#list" or something to that effect. I don't understand why that is
happening if the action is indeed there?!

I think that I may use a pre-fab authentication controller after all.
This is giving me a headache. Thanks again to all of you for the help.

Greg
This topic is locked and can not be replied to.