How to do Stateless User Authentication of My App - ruby-on-rails

Update from comments: I want to do Stateless of Restful in HTTP connection. My goal is making a system that when users log into my app, my app's server assigns an id to them. Because if my app cannot do so, other users can access a user pages (if they write something in the URL randomly). And my server's model have users' ids in that time. When users log out my app, these ids are deleted from model. Maybe I can call these system 'Session'.
I am performing user authentication in my app. I want to realize Stateless in there that it pass id to users when they log in my app. However, I'm a beginner, so I don't know how to do it. I think I should write these codes in the main controller, but am not sure. How can I do this process?
home_controller
class HomeController < ApplicationController
before_filter :find_user, only: [:index]
def index
#id = params[:id]
#email = [:email]
if #id == #user.id && #email == #user.email
render :text => "sucsess"
else
render :text => "fail"
end
end
def create
userData = UserData.new(create_params)
user = User.find(params[:id]).to_json
# エラー処理
unless userData.save
#error_message = [memo.errors.full_messages].compact
end
end
private
   def find_user
#user = User.find(params[:id]) # You should specify this code what are your comparing to.
end
end
routes.rb
Rails.application.routes.draw do
devise_for :users
root to: "home#index"
get 'home/index'
namespace :home, default: {format: :json} do
resources :index, only: :create
end
end
user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable
end

When a user logs in via Devise, they are given a unique token that is stored in the browser's session. When the next page is rendered, the browser will pass it's session cookie to the rails app, and Devise will gather the user token from the session cookie and populate the current_user variable with the user object that matches that token.
So if you follow the instructions for setting up Devise in its README, then once a user has logged in, you can access that logged in user's User object via current_user

Related

Couldn't find User without an ID even when #user with params is created

I created a Rails app with Devise.
Each User should be able to reply to a form which populates the model Questionone.
However, I keep getting Couldn't find User without an ID
What I did:
rails generate scaffold Questionone first_question:text second_question:text user:references
In my User.rb
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :questionones
end
In my Questionone.rb i have:
class Questionone < ApplicationRecord
belongs_to :user
end
In my questiones_controllers
before_action :set_questionone, only: [:show, :edit, :update, :destroy]
def new
#questionone = Questionone.new
#user = User.find(params[:user_id])
#If I use #user = current_user.id it works, but not sure if is right way
end
def create
#questionone = Questionone.new(questionone_params)
#questionone.user = User.find(params[:user_id])
#questionone.save
end
private
# Use callbacks to share common setup or constraints between actions.
def set_questionone
#questionone = Questionone.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def questionone_params
params.require(:questionone).permit(:user_id, :first_question, :second_question)
end
end
If I use a raise, it tells me that #user is nil
IF I USE #user = current_user.id it works, but I am not sure it is the right way to go
A bit of faulty logic there. Here is the answer:
def new
#questionone = Questionone.new
#user = current_user
end
def create
#questionone = Questionone.new(questionone_params)
#questionone.user = current_user
#questionone.save
end
Also, you are not memoizing the Questionone (? weird name :D ), you should do it like this:
def set_questionone
#questionone ||= Questionone.find(params[:id])
end
The longer answer:
I believe the user scope should be limited to the one that is currently login. If that's correct, then you are introducing a serious security problem in which anyone can create questions by pushing a user_id in the params.
Remove the user_id param entirely and use the current_user variable.

Error Ruby on Rails: Users::OmniauthCallbacksController#facebook is missing a template for this request format and variant

I'm trying to add an external login with facebook, but whenever I realize the home page correctly directs me to the facebook page, but then I get the following error, and could not understand what it can be.
"Users::OmniauthCallbacksController#facebook is missing a template for this request format and variant. request.formats: ["text/html"] request.variant: [] NOTE! For XHR/Ajax or API requests, this action would normally respond with 204 No Content: an empty white screen. Since you're loading it in a web browser, we assume that you expected to actually render a template, not nothing, so we're showing an error to be extra-clear. If you expect 204 No Content, carry on. That's what you'll get from an XHR or API request. Give it a shot."
"That's what you'll get from an XHR or API request. Give it a shot."
raise ActionController::UnknownFormat, message
else
logger.info "No template found for #{self.class.name}\##{action_name}, rendering head :no_content" if logger
super
this is my controller
class Users::OmniauthCallbacksController < ApplicationController
def facebook
#User = User.from_omniauth(request.env["omniauth.auth"])
if #User.persisted?
#User.remember_me = true
sign_in_and_redirect #User, event: :authentication
end
end
end
this is the user model.
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,:omniauthable, :omniauth_providers => [:facebook]
def self.from_omniauth(auth)
where(provider: auth[:provider], uid: auth[:uid]).first_or_create do |user|
if auth[:info]
user.email = auth[:info][:email]
user.name = auth[:info][:name]
end
user.password = Devise.friendly_token[0,20]
end
end
has_many :articles , :dependent => :destroy
end
and i put this line in config/initializers/divise.rb
config.omniauth :facebook, '504432376574467', 'b2bb80641fcc2ca4d28e48c5ce*******'
My guess would be that User.from_omniauth fails to create the user (possibly due to user.password and user.password_confirmation not matching), which causes the Users::OmniauthCallbacksController#facebook to reach the end of the method without going inside the if clause.
To check, you could for example add an else clause to your Facebook callback and raise an error in there.

Setting up different User models and registration paths for Devise on Ruby on Rails

I am very new to ruby and I have been really struggling with this for months. I searched extensively and tried what the answers said but still no luck. (I tried Multiple user models with Ruby On Rails and devise to have separate registration routes but one common login route but didnt work)
I currently have a user.rb model and it is connected to devise and works fine.
1- On the sign-up page, I would like to have 3 buttons that would lead to separate registration forms (one each for business, manager and the already existing user). Do I set this up in routes.rb?
2- The forms will have different attributes that will populate their respective databases.
3- After completion of the form they will be directed to their respective routes. User to the current default route while business to the business dashboard and manager to the manager dashboard. Is this again in routes.rb or devise?
I would greatly appreciate any guidance!
I've read through the documentations for devise, cancan and rolify but I can't seem to bring it all together to work for me.
I am very new to ruby and I have been really struggling with this for months. I searched extensively and tried what the answers said but still no luck. (I tried Multiple user models with Ruby On Rails and devise to have separate registration routes but one common login route but didnt work)
I currently have a user.rb model and it is connected to devise and works fine.
1- On the sign-up page, I would like to have 3 buttons that would lead to separate registration forms (one each for business, manager and the already existing user). Do I set this up in routes.rb?
2- The forms will have different attributes that will populate their respective databases.
3- After completion of the form they will be directed to their respective routes. User to the current default route while business to the business dashboard and manager to the manager dashboard. Is this again in routes.rb or devise?
I would greatly appreciate any guidance!
I've read through the documentations for devise, cancan and rolify but I can't seem to bring it all together to work for me.
#user.rb
class User < ActiveRecord::Base
has_many :contibutions
rolify
# Include default devise modules. Others available are:
# :lockable, :timeoutable
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable
validates_format_of :email, :without => TEMP_EMAIL_REGEX, on: :update
def admin?
has_role?(:admin)
end
def self.find_for_oauth(auth, signed_in_resource = nil)
# Get the identity and user if they exist
identity = Identity.find_for_oauth(auth)
user = identity.user
if user.nil?
# Get the existing user from email if the OAuth provider gives us an email
user = User.where(:email => auth.info.email).first if auth.info.email
# Create the user if it is a new registration
if user.nil?
user = User.new(
name: auth.extra.raw_info.name,
#username: auth.info.nickname || auth.uid,
email: auth.info.email.blank? ? TEMP_EMAIL : auth.info.email,
password: Devise.friendly_token[0,20]
)
user.skip_confirmation!
user.save!
end
# Associate the identity with the user if not already
if identity.user != user
identity.user = user
identity.save!
end
end
user
end
end
I'd go with one User model and a two stage signup. First they would click on their desired button, each one passing a unique 'role' param in the URL and going to the devise signup page. Here they would enter only their email/password and we would pass the param from the URL to a simple 'role' hidden field in the form.
Then as step 2, after technically registering, they are directed to a separate edit account type page (each user having a different account, outlined below) to fill in the rest of their details.
The models:
models/user.rb
class User < ActiveRecord::Base
has_one :account
has_one :business_account
has_one :manager_account
end
models/account.rb
class Account
belongs_to :user
models/business_account.rb
class BusinessAccount
belongs_to :user
models/manager_account.rb
class ManagerAccount
belongs_to :user
Then, using devise, I'd override the registrations_controller to add a role based on a hidden field in the first step simple registration form (which would just be email/password/role).
In that file, I'd also override the after_signup_path method, to redirect to an edit_account type page for the relevant account we create for them during signup.
First the routes:
devise_for :users, :controllers => {:registrations => "registrations"}
resources :users do
resource :account
resource :business_account
resource :manager_account
end
Then the controller (see comments within code):
controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def create
build_resource(sign_up_params)
if resource.save
# you will name the following param. make sure it's in devise strong_params
# also the == will depend on how you pass the role - string, integer etc
if sign_up_params[:role] == "1"
user.add_role :standard
resource.build_account(user_id: resource.id) # code to create user account
elsif sign_up_params[:role] == "2"
user.add_role :manager
resource.build_manager_account(user_id: resource.id) # code to create user account
elsif sign_up_params[:role] == "2"
user.add_role :business
resource.build_business_account(user_id: resource.id) # code to create user account
end
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_navigational_format?
sign_up(resource_name, resource)
respond_with resource, :location => after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format?
expire_session_data_after_sign_in!
respond_with resource, :location => after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
respond_with resource
end
end
protected
# override the after signup path to your desired route, e.g
def after_sign_up_path_for(resource)
if sign_up_params[:role] == "1"
edit_user_account_path(resource.id)
elsif sign_up_params[:role] == "2"
edit_user_manager_account_path(resource.id)
elsif sign_up_params[:role] == "2"
edit_user_business_account_path(resource.id)
end
end
end
The above would redirect them to a separate accounts controller/view depending on the account type. This solution would save you a lot of headaches down the line.

Using one sign-in form with two Devise user models and different authentication methods

I'm building a site that must support authentication both via LDAP, and with 'local' users that are managed in the site only.
Currently I have the following Devise models:
class User < ActiveRecord::Base
end
class LdapUser < User
devise :ldap_authenticatable, :rememberable, :trackable
end
class LocalUser < User
devise :database_authenticatable, :registerable, :confirmable, :recoverable, :trackable
end
Devise is generating routes that are separate for each of these, i.e. /local_users/sign_in and /ldap_users/sign_in. This isn't ideal, users shouldn't need to know which type of user they are, so I'd like to unify it all into one form, with one set of sign in/out URLs.
I've looked at some solutions for how to do this, but they seem to rely on the fact that the models have the same Devise configuration, or the same authentication method.
The only other example online of this sort of problem that I've found is this Google Groups thread: https://groups.google.com/forum/#!topic/plataformatec-devise/x7ZI6TsdI2E - which hasn't been answered.
This has taken me quite a while to figure out, but I've eventually got a working solution.
I also want to give most of the credit for this to Jordan MacDonald who posted the question I mentioned above in the Devise Google Group. While that thread didn't have an answer on it, I found the project he had been working on, read the code and adapted it to my needs. The project is Triage and I highly recommend reading the implementations of SessionController and the routes.
I also recommend Jordan's blog post on Devise: http://www.wastedintelligence.com/blog/2013/04/07/understanding-devise/
Model
As above, my model is as follows, and I'm using the gem devise_ldap_authenticatable. In this example, I have two users, LdapUser and LocalUser, but I see no reason why this wouldn't work for any two Devise user models, as long as you have some way of differentiating between them.
class User < ActiveRecord::Base
end
class LdapUser < User
devise :ldap_authenticatable, :rememberable, :trackable
end
class LocalUser < User
devise :database_authenticatable, :registerable, :confirmable, :recoverable, :trackable
end
Controller
The first part we need is the controller. It should inherit from Devise::SessionsController, and it chooses which type of user we are authenticating, then explicitly passing this on to the authentication stage, which is handled by Warden.
As I was using LDAP against an Active Directory domain for one part of the authentication, I could easily tell which details should be authenticated against LDAP, and which shouldn't, but this is implementation specific.
class SessionsController < Devise::SessionsController
def create
# Figure out which type of user we are authenticating.
# The 'type_if_user' method is implementation specific, and not provided.
user_class = nil
error_string = 'Login failed'
if type_of_user(request.params['user']) == :something
user_class = :local_user
error_string = 'Username or password incorrect'
else
user_class = :ldap_user
error_string = 'LDAP details incorrect'
end
# Copy user data to ldap_user and local_user
request.params['ldap_user'] = request.params['local_user'] = request.params['user']
# Use Warden to authenticate the user, if we get nil back, it failed.
self.resource = warden.authenticate scope: user_class
if self.resource.nil?
flash[:error] = error_string
return redirect_to new_session_path
end
# Now we know the user is authenticated, sign them in to the site with Devise
# At this point, self.resource is a valid user account.
sign_in(user_class, self.resource)
respond_with self.resource, :location => after_sign_in_path_for(self.resource)
end
def destroy
# Destroy session
end
def new
# Set up a blank resource for the view rendering
self.resource = User.new
end
end
Routes
Devise sets up lots of routes for each type of user, and for the most part we want to let it do this, but as we are overriding the SessionsController, so need it to skip this part.
After it has set up its routes, we then want to add our own handlers for sign_in and sign_out. Note that the devise scope being local_user doesn't matter, it just needs a default scope, we are overriding this in the controller anyway. Also note that this is local_user singular, this caught me out and caused lots of trouble.
devise_for :ldap_users, :local_users, skip: [ :sessions ]
devise_scope :local_user do
get 'sign_in' => 'sessions#new', :as => :new_session
post 'sign_in' => 'sessions#create', :as => :create_session
delete 'sign_out' => 'sessions#destroy', :as => :destroy_session
end
View
The view is very simple, and can modified without causing too many issues.
<div>
<%= form_for(resource, :as => 'user', url: create_session_path) do %>
<fieldset>
<legend>Log In</legend>
<label>LDAP Username or Database Email</label>
<input type="text" placeholder="Username or Email" name="user[email]" />
<label>Password</label>
<input type="password" placeholder="Password" name="user[password]" />
<input type="submit" class="button" value="Log In" />
</fieldset>
<% end %>
</div>
I hope this helps someone else. This is the second web app I've worked on that had to have both LDAP and local authentication (the first being a C# MVC4 application), and both times I've had significant trouble getting authentication frameworks to handle this nicely.

Rails 4 devise , How to sign up new users if signed in?

I want to block signup for non-admins so that only a superuser/administrator can add new users. How can I achieve that?
I tried following the method mentioned here: Devise before filter that prevents access to “new_user_registration_path” unless user is signed-in but had no results.
I have installed devise, cancan and rolify. In addition, I also don't want anyone to go to the /users/sign_up page and sign in. Only admins must have the ability to sign up new users.
Due to the devise installation there is no users controller. Please guide me through making one if needed.
routes.rb
FifthApp::Application.routes.draw do
devise_for :users
resources :qanotes
end
user.rb
class User < ActiveRecord::Base
#resourcify :resources
rolify
has_many :qanotes
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
I keep on getting redirected to the root, i.e. localhost:3000, when I try to go to sign up page (only after log in).
Remove :regesterable keyword from default devise modules from your user model. Than you should add your own form for creating new user, and thus you can add new users.
Hope it will help. Thanks
You could customize registration controller (e.g registrations_controller.rb), and you should add before_filter authentication and before_filter only administrator to registrations_controller.rb looks like :
class RegistrationsController < Devise::RegistrationsController
before_filter :authenticate_user!
before_filter :is_administratior?, only: [:new, :create]
def new
super
end
def create
super
end
private
def is_administratior?
if user_signed_in? # if user signed
if current_user.administrator? # if adminstrator return true
true
else
redirect_to some_path
end
else
redirect_to login_path
end
end
See my answer here about Devise/cancan redirect admin

Resources