Very nice solution, but is there a specific reason to not use Boolean tables within the user model for each role ? (user.amin, user.moderator etc.) It seems to be easier this way to delete roles and all the corresponding data through migrations.
To get the ball rolling - here are some example gists that show how to do 'remember me' and 'redirect to target page'.
'remember me' sets a cookie. if the person kills the browser, then opens a new session and returns to the page, the user will be auto logged in. cookie times out in 100 hours.
'redirect to target page' sets the referring URL in the protected controller (using authenticate_member!). then after the person logs in, they are redirected to the page they wanted.
Using this screencast, I was able to get rid of Devise in about 20 minutes. THANKS!!
I think a lot of people would benefit from a screencast that shows 'advanced' authentication options like: remember me, forgot password, session timeouts, email registrations confirmations, ...
Is it possible to have a nested model solution, for example, where each painting requires that you upload three images instead of just one, and then stores them in an Images table with a painting_id column and gallery_id column, instead of just an images column in the Paintings table?
Im trying to do this and having trouble getting the logic down.
Anybody know a way to "un" force_ssl? I've got it set on one controller, but if a user clicks a relative link on my page, I want to revert to http. I can think of a few ways, but they're all pretty nasty. Hoping there's a simpler way.
Be very careful with this. The query you use will fetch all the users and puts LOWER to it. If you have 100.000 users, it will fetch them all and it wont use indexes.
It is better you put after create filters to lower case the email address.
Personally, I find using a 'login' method that takes a username (or email if you like) and a password is shorter and nicer than 2 lines of first finding the user in the db and then checking for the password explicitly.
lazylester, you are getting philosophical here. In this screencast there is no way to ensure that you are who you say you are at signup, but the achievement here is to authenticate you every other time afterwards, since there is a password attached to your user model.
Now, we could wait for confirmation (like in devise) from the given email address, but... who ensures us that the given email address really represents the person who you say you are? Since there are so many ways to cheat that confirmation procedure, the extra check doesn't give us a 100% security. Therefore, even though this is a worthy discussion, I find your comment a little out of place.
a lot of people want people to register to see content, that way they can send mass e-mails, say that have x users, etc. If you want to have manual activation it's not that hard, just add an extra field such as add_column :users, :activated, :boolean, :default => false, :null => false and then have an admin panel and set user.activated = true on your users.
I remember that I've done something similar before but used flash.now.success and got an error that success was undefined, is it only selected names or was it something else I did wrong? (It was so long ago and it's a pain to create a controller to test them XD)
What do I mean? Well the screencast is titled "Authentication in Rails 3.1", and yes, authentication means proving you are who you claim to be. But the sign-up procedure doesn't do that. (Does it? How?)
You say, Sean, that authentication means that you can modify your own resources and not other peoples. That's authorization, not authentication.
I'm not seeing how sign-up supports authentication. But I can be a bit dense sometimes! So be gentle!
I have previously used devise for authentication but think it is to heavy with too many functions and too much I have to customize. This new built-in methods are really nice.
In devise you use a before_filter to authenticate certain actions, e.g.
some_controller
before_filter :authenticate_user!
How can I do the same thing without using devise and instead use the new methods?
Yes, it is safe to store the user_id in a session. If you're using cookie based sessions then the client can read the data inside, but they can't write to it. Basically you don't have to worry about someone changing the session, but you do have to be careful to not store sensitive information in there (such as the user's passwords).
On the surface they do basically the same thing: redirect to https, but at different levels. Apache/Nginx will redirect before it ever hits the Rails app, so it will be quicker and it won't go through the Rack middleware stack at all.
The force_ssl call in the controller happens in a before_filter so it will happen later. The main benefit of this is that you can add/remove it for certain actions and use any Ruby logic you want. If you want every page in your app to use SSL then doing it at the web server level is probably best.
There is also a config.force_ssl = true option you can place in your app config which will use middleware and redirect every page. That is closer to Apache/Nginx solution but is nice if you don't have access to that config such as on Heroku.
Hello! This is certainly not the first time I am implementing authentication, but the question rises again, as I need it in a social website.. is using session[:user_id] safe by default?
Great screencast. I have a couple of questions though after watching it. I noticed that you are using a couple of 'old school' methods in your code which I thought were not considered the 'Rails 3' way of doing things. I'm referring to:
user = User.find_by_email(params[:email])
and
validates_presence_of :password, :on => :create
Is this still considered good practice in Rails 3 when we have the alternatives?
What do you mean? Thousands of sites/apps allow user sign up, but still require authentication to make sure a given user is who she claims to be. Authentication just means that you can add/change/delete resources, settings, etc. under your own account and not anyone else's. This screencast focussed only on the authentication side of things, but the developer is responsible for authorization, which is highly dependent on the kind of app being developed. Usually authentication is a bit more generic.
Same question for apache, I have apache/passenger forcing a rewrite on all pages to the https equivalent. would the force_ssl replace the need for that rewrite?
I noticed you used "flash.now.warning" = instead of "flash.now[:warning] =". I was curious about it but it doesn't work in 3.1RC4. Was this just a mistake or is there a plugin that has this functionality?
If you need something like hash_secure_password on Rails 3.0.x, you can use my plugin at https://github.com/SMWEB/salt-and-pepper . As a bonus, it only uses a single column in the database and doesn't force you to call your attribute "password".
Very nice solution, but is there a specific reason to not use Boolean tables within the user model for each role ? (user.amin, user.moderator etc.) It seems to be easier this way to delete roles and all the corresponding data through migrations.
To get the ball rolling - here are some example gists that show how to do 'remember me' and 'redirect to target page'.
'remember me' sets a cookie. if the person kills the browser, then opens a new session and returns to the page, the user will be auto logged in. cookie times out in 100 hours.
'redirect to target page' sets the referring URL in the protected controller (using authenticate_member!). then after the person logs in, they are redirected to the page they wanted.
Login Form: https://gist.github.com/1032488
Sessions Controller: https://gist.github.com/1032490
Application Controller: https://gist.github.com/1032492
I second andyl's suggestion
Using this screencast, I was able to get rid of Devise in about 20 minutes. THANKS!!
I think a lot of people would benefit from a screencast that shows 'advanced' authentication options like: remember me, forgot password, session timeouts, email registrations confirmations, ...
One thing you missed in this Tutorial is .
Adding :username in accessible mode in user.rb (user model)
other
Same problem here. On local server is working, but when pushing to heroku I have this issue.
I use this functionality on many controllers, and extracted common controller actions as a module: https://gist.github.com/1030815
Is it possible to have a nested model solution, for example, where each painting requires that you upload three images instead of just one, and then stores them in an Images table with a painting_id column and gallery_id column, instead of just an images column in the Paintings table?
Im trying to do this and having trouble getting the logic down.
@Alexey Poimtsev
Because you're missing the :validatable module from Devise which adds the password_required? method.
Anybody know a way to "un" force_ssl? I've got it set on one controller, but if a user clicks a relative link on my page, I want to revert to http. I can think of a few ways, but they're all pretty nasty. Hoping there's a simpler way.
Thanks in advance for any help!
I think you are confusing authentication and authorisation.
Authentication is only to make sure you are who you claim to be logging on.
You are talking about authorization which defines if you are allowed to access determined parts of an application/data.
I like this but can't figure out how to override the duplicate validation errors when say the
password
field is left blank:"Password digest" means NOTHING to a user. How can we suppress this first error when the validator is in Rails 3.1 source?
I found out the
get some trouble on heroku. It tries to install it even if it specified on group :test, :development. I commented it and it works fine
Anybody know how to create a fixture (traditional YAML style) for a model using
has_secure_password
?Hi ! Really nice tutorial. Everything work without AJAX :( It
s mean keyup :( I
don`t now why.Be very careful with this. The query you use will fetch all the users and puts LOWER to it. If you have 100.000 users, it will fetch them all and it wont use indexes.
It is better you put after create filters to lower case the email address.
Personally, I find using a 'login' method that takes a username (or email if you like) and a password is shorter and nicer than 2 lines of first finding the user in the db and then checking for the password explicitly.
See my gem https://github.com/NoamB/sorcery for an example (wiki).
lazylester, you are getting philosophical here. In this screencast there is no way to ensure that you are who you say you are at signup, but the achievement here is to authenticate you every other time afterwards, since there is a password attached to your user model.
Now, we could wait for confirmation (like in devise) from the given email address, but... who ensures us that the given email address really represents the person who you say you are? Since there are so many ways to cheat that confirmation procedure, the extra check doesn't give us a 100% security. Therefore, even though this is a worthy discussion, I find your comment a little out of place.
the way BCrypt is, is really cool. Here is a password_digest:
$2a$10$QIFk4ytMIzE03/njtSMFmedzhTyv8DVMMtWjqnFeW9FcQpBEf.u0.
I believe 2a or $2a is the salt, $10 means 10 encryptions/stretches and the rest after the next $ (or included) is the resultant hash.
I don't like them since they take longer, sure it's by uncountable times, but it's really not too much for me to add the extra code. Also I do this:
a lot of people want people to register to see content, that way they can send mass e-mails, say that have x users, etc. If you want to have manual activation it's not that hard, just add an extra field such as
add_column :users, :activated, :boolean, :default => false, :null => false
and then have an admin panel and set user.activated = true on your users.I remember that I've done something similar before but used
flash.now.success
and got an error that success was undefined, is it only selected names or was it something else I did wrong? (It was so long ago and it's a pain to create a controller to test them XD)*has_secure_password ;P
Yeah, I don't know why they aren't accepting pull requests that allow you to rename what column it goes into.
In Mongoid 2.0 (and I believe 2.0.1 as well) you need to include the following in your model if you're going to use Date or DateTime
include Mongoid::MultiParameterAttributes
Source: https://github.com/mongoid/mongoid/issues/30#issuecomment-1211911
What do I mean? Well the screencast is titled "Authentication in Rails 3.1", and yes, authentication means proving you are who you claim to be. But the sign-up procedure doesn't do that. (Does it? How?)
You say, Sean, that authentication means that you can modify your own resources and not other peoples. That's authorization, not authentication.
I'm not seeing how sign-up supports authentication. But I can be a bit dense sometimes! So be gentle!
Just the same as in the controller
The pasword hashing is done internally.
What about creating a user via the console? I can't find any methods for creating the password_digest.
Something like this in the ApplicationController.
Yes, CanCan just relies on a
current_user
method. It is compatible with pretty much any type of authentication.Hi,
I have previously used devise for authentication but think it is to heavy with too many functions and too much I have to customize. This new built-in methods are really nice.
In devise you use a
before_filter
to authenticate certain actions, e.g.How can I do the same thing without using devise and instead use the new methods?
BCrypt stores the salt with the password hash I believe.
Eric,
Dynamic finders (
User.find_by_email
etc.) are not deprecated or old school in Rails 3.Hi Ryan:
As always, a wonderful screencast.
Is CanCan compatible with the new Rails 3.1 authentication?
Thanks,
-Alex
No password salt?
The validates alternative would be.
Both alternatives are longer so I don't know if they are necessarily better. The other way may be deprecated in 3.1, I haven't checked yet.
Yes, it is safe to store the
user_id
in a session. If you're using cookie based sessions then the client can read the data inside, but they can't write to it. Basically you don't have to worry about someone changing the session, but you do have to be careful to not store sensitive information in there (such as the user's passwords).Are you referring to
flash.now.alert=
? That was working in the episode and is available in older versions as well.On the surface they do basically the same thing: redirect to https, but at different levels. Apache/Nginx will redirect before it ever hits the Rails app, so it will be quicker and it won't go through the Rack middleware stack at all.
The
force_ssl
call in the controller happens in abefore_filter
so it will happen later. The main benefit of this is that you can add/remove it for certain actions and use any Ruby logic you want. If you want every page in your app to use SSL then doing it at the web server level is probably best.There is also a
config.force_ssl = true
option you can place in your app config which will use middleware and redirect every page. That is closer to Apache/Nginx solution but is nice if you don't have access to that config such as on Heroku.Hello! This is certainly not the first time I am implementing authentication, but the question rises again, as I need it in a social website.. is using
session[:user_id]
safe by default?arguments:
http://stackoverflow.com/questions/623379/rails-tracking-a-users-id#answer-623463
http://www.issociate.de/board/post/475749/Is_it_safe_to_store_user_id_in_Session?.html
Great screencast. I have a couple of questions though after watching it. I noticed that you are using a couple of 'old school' methods in your code which I thought were not considered the 'Rails 3' way of doing things. I'm referring to:
user = User.find_by_email(params[:email])
and
validates_presence_of :password, :on => :create
Is this still considered good practice in Rails 3 when we have the alternatives?
user = User.where(:email => params[:email]).first
and
validates :password, :on => :create
Thanks for your help!
What do you mean? Thousands of sites/apps allow user sign up, but still require authentication to make sure a given user is who she claims to be. Authentication just means that you can add/change/delete resources, settings, etc. under your own account and not anyone else's. This screencast focussed only on the authentication side of things, but the developer is responsible for authorization, which is highly dependent on the kind of app being developed. Usually authentication is a bit more generic.
Same question for apache, I have apache/passenger forcing a rewrite on all pages to the https equivalent. would the force_ssl replace the need for that rewrite?
I'm probably missing something obvious here. But what is the use case for the "sign up" authentication method?
If anyone can sign up and set up a password, isn't the site just as unprotected as a site with no password?
Remove the dot in the end of the url.
[Ryan Bates: fixed it]
I noticed you used "flash.now.warning" = instead of "flash.now[:warning] =". I was curious about it but it doesn't work in 3.1RC4. Was this just a mistake or is there a plugin that has this functionality?
Is there any way to get image dimensions in my view?
@user.avatar_width(:thumb)
or@user.avatar_height(:thumb)
Something like this?
If you need something like hash_secure_password on Rails 3.0.x, you can use my plugin at https://github.com/SMWEB/salt-and-pepper . As a bonus, it only uses a single column in the database and doesn't force you to call your attribute "password".
Ryan, is the "force_ssl" needed if nginx setup with force ssl redirection?
brilliant thanks demetrios, I'm not fluent enough with textmate to know where to start looking for these things
for some reason I had to had angle brackets around my prePopulate setting like so:
not quite sure why, could be because my fields are single value.