I have set up a test applications and have setup devise to take care of the authentication, additionally I have set up a component where they are sent to a create profile page after registration which works well.
The problem I have is when a logged in user goes to edit they're profile it is easy for then to change the query string and access another users data -
http://localhost:3000/profiles/1/edit
the question i have is how do I lock this down to the current user so that can only edit they're data?
Robbie
I would go for a before_filter.
# in profiles controller
class ProfilesController < ApplicationController
before_filter :find_profile
before_filter :check_if_authorized
def find_profile
#profile = Profile.find(params[:id])
end
def check_if_authorized
render :status => 404 and return unless current_user == #profile.user
end
end
Assumptions:
devise model is named User
user has one profile
you're already checking if a user is logged in
You can use token authentication along with session for more precise and secure authentication.
Add devise :token_authenticatable to the model User
This will create an authentication token into the field authentication_token field of users table every time a user is created.
Then go for a before_filter :verify_auth_token
def verify_auth_token
if current_user.authentication_token == params[:auth_token]
return true
else
return false
end
end
Also the edit request should be http:///profiles/1/edit?auth_token=12wqaasaeaad
Related
I'm trying to create admin roles that can go in and change other users information. I've already got everything set up pretty much except that I can't get the edit method to select the correct user to update.
Looking in the devise code, it looks like I need to update the resource to be the user of the profile that's being selected instead of the current user (which would be the admin).
How do I go about updating the resource that is sent into the devise edit view and update action? It looks like it might have something to do with this
def authenticate_scope!
send(:"authenticate_#{resource_name}!", :force => true)
self.resource = send(:"current_#{resource_name}")
end
So for example, what I want to do is
def update_resource
self.resource = User.find(params[:id])
end
Is this possible?
We have an existing user base and are adding email confirmation. Confirmation is optional but will allow additional features. Users are not required to confirm. I've added the confirmable module and ran migrations. Confirmation works as advertised.
But, users cannot log in since they are not confirmed. All current users have nil confirmation values, which is what we want (users can go back and confirm their email at any time). I've followed all the Devise wiki articles and set allow_unconfirmed_access_for in the initializer:
config.allow_unconfirmed_access_for = 10.years
I've also tried setting it in our user model as well:
devise :confirmable, allow_unconfirmed_access_for: 10.years
I've also tried using other values (1.year, 500.days, etc.)
My SessionsController, which does not differ much from Devise's method (here on github)
class Users::SessionsController < Devise::SessionsController
respond_to :json
def new
redirect_to "/#login"
end
def create
resource = warden.authenticate(auth_options)
if !resource
render json: {error: "Invalid email or password" }, status: 401 and return
end
sign_in(resource_name, resource)
render "sign_in", formats: [:json], locals: { object: resource }
end
end
Devise's the response:
{"error": "You have to confirm your account before continuing."}
Devise 2.1.2 with Rails 3.2.9.
The Devise team have released a version (2.2.4) that supports nil as a valid value for allow_unconfirmed_access_for, meaning no limit. Issue: https://github.com/plataformatec/devise/issues/2275
You can now do:
config.allow_unconfirmed_access_for = nil
I simply needed to do this in my User model, instead of using allow_unconfirmed_access_for:
protected
def confirmation_required?
false
end
I've got the same issue: after turning on devise confirmations previously created accounts are unable to login.
The reason is here:
def confirmation_period_valid?
self.class.allow_unconfirmed_access_for.nil? || (confirmation_sent_at && confirmation_sent_at.utc >= self.class.allow_unconfirmed_access_for.ago)
end
Old accounts have confirmation_sent_at set to nil, that's why they are unable to log in.
One solution is to force confirmation_sent_at like that:
update users set confirmation_sent_at=created_at where confirmation_sent_at is NULL;
You can do it manually, or create a migration.
i am following this tutorial http://eveloverails.wordpress.com/2011/04/02/183/. I have created the users through devise and i want when the user log in as an admin he should have the list of users in which it can edit the permissions of the users like edit destroy,etc.
Thanks in advance
you can add a field in devise model call role. then create cancan ability class in your model then define your authorization like
class Ability
include CanCan::Ability
def initialize(user)
# Define abilities for the passed in user here. For example:
user ||= Login.new # guest user (not logged in)
if user.role == 'admin'
can :manage, :all
else
can :read, :all
end
end
end
See the wiki for details: https://github.com/ryanb/cancan/wiki/Defining-Abilities
I have a scenario where i need to restrict users from having only one active session at a time. Mine is a rails3 application and uses devise for authentication. I'm interested in keeping only the latest user session active. i.e., if a user logs in while there is another session active for the same username, i want to inactivate the older session and allow the recent one. Is there a way, in devise, to get hold of user sessions and invalidate them?
You can track a particular user's session by storing a unique token specific to that user in the database.
Create a migration to add the field for storing the token. I assume the devise model is User.
class AddSignInTokenToUsers < ActiveRecord::Migration
def change
add_column :users, :current_sign_in_token, :string
end
end
Add the following code to application_controller.rb
class ApplicationController < ActionController::Base
before_filter :invalidate_simultaneous_user_session, :unless => Proc.new {|c| c.controller_name == 'sessions' and c.action_name == 'create' }
def invalidate_simultaneous_user_session
sign_out_and_redirect(current_user) if current_user && session[:sign_in_token] != current_user.current_sign_in_token
end
def sign_in(resource_or_scope, *args)
super
token = Devise.friendly_token
current_user.update_attribute :current_sign_in_token, token
session[:sign_in_token] = token
end
end
sign_in(resource_or_scope, *args) is a devise hook that will be called every time the user logs in.
invalidate_simultaneous_user_session will log out the current user if another instance of the current user logs in. This will ensure that only one session is active for a user at any instance of time.
invalidate_simultaneous_user_session filter should be skipped for the user login action to update the newly logged in user's token. I am not happy with using a Proc to skip the filter based on controller name and action. If you have already overridden devise's sessions_controller, then include skip_before_filter :check_simultaneous_user_session inside that controller and you can get rid of the Proc!
Hope this helps..
For updated devise for rails 4,
you may change the code according to this
http://pastebin.com/p6mvC8T3
I'm trying to redirect the user if their account hasn't been confirmed. So this involves two parts of the code:
Redirect the user after they first create the account
Redirect them if they try to sign in before confirming the account
I need help with the second.
The first I was able to do by putting in after_inactive_sign_up_path_for(resource) in my custom RegistrationsController. I've tried to do the same for a SessionsController, but it didn't work. What do I need to over write in order to properly redirect the user if they haven't confirmed the account yet?
You may have to create a custom warden strategy and check if the account needs confirmation. Something of this sorts:
# config/initializers/my_strategy.rb
Warden::Strategies.add(:my_strategy) do
def valid?
true
end
def authenticate!
u = User.find_for_authentication(:email => params[:email])
if u.nil? || !u.valid_password?(params[:password])
fail(:invalid)
elsif !u.confirmed?
fail!("Account needs confirmation.")
redirect!("your_root_url")
end
else
success!(u)
end
end
#config/initializers/devise.rb
config.warden do |manager|
manager.default_strategies(:scope => :user).unshift :my_strategy
end
This assumes the username and password are passed in the request as params. You can look at the database_authenticable strategy for an example of how Devise deals with sign-in authentication by default.