# Authentication and user management questions

**URL:** <https://www.ruby-forum.com/t/authentication-and-user-management-questions/161306>\
**Category:** Rails\
**Created:** [February 25, 2009, 9:47am UTC](https://www.ruby-forum.com/t/authentication-and-user-management-questions/161306 "2009-02-25T09:47:40Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![sa125](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b4bc9f/32.png) [@sa125](https://www.ruby-forum.com/u/sa125)\
**Post date:** [February 25, 2009, 9:47am UTC](https://www.ruby-forum.com/t/authentication-and-user-management-questions/161306/1 "2009-02-25T09:47:40Z")

</div>

Hi -

I am using a fairly standard authentication in my app (user model,  
before\_filter in application\_controller). This authentication is taken  
almost entirely from the 3rd ed. of the agile web dev w/ rails. A few  
questions about all that -

1. I’m still in dev environment, but I noticed that I’m not being logged  
out between sessions. I even restarted my machine and pointed my browser  
to a page, and wasn’t taken to the login page first. Only if I  
explicitly invoke the logout action does it actually log me out. How do  
I force a logout between sessions? I tried clearing the sessions table  
(rake db:sessions:clear) but that didn’t do it.

2. what’s a good way to implement automatic logout after some  
inactivity?

3. I have many users and need to manage different permission levels.  
Some users should be able to see and edit a certain page, others need to  
view only, and some shouldn’t be able to access certain pages. What  
would be a good way to manage that? I thought about creating a page  
model and controller, and then using some joined table page\_users or  
something that keeps the user\_id, page\_id and the different boolean  
permissions (can\_view, can\_edit, etc…). Then I’d probably need to add a  
before\_filter in each controller/action…

I’m quite new to rails, so I’d love to hear any better or more efficient  
ideas - thanks.

---

<div class="post-metadata">

**Author:** ![sa125](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b4bc9f/32.png) [@sa125](https://www.ruby-forum.com/u/sa125)\
**Post date:** [February 25, 2009, 10:40am UTC](https://www.ruby-forum.com/t/authentication-and-user-management-questions/161306/2 "2009-02-25T10:40:16Z")

</div>

for your permissions problem I’d suggest the implementation of roles  
or groups. that way you can add users to groups or give them roles,  
which can be checked in a before\_filter in your controllers.

sessions:  
if you are using activerecordstore (and thus your sessions are saved  
in a db-table) deleting those entries should result in a logout. there  
should be configuration in your environment like this:  
config.action\_controller.session\_store = :active\_record\_store

if you clean that table and you are still logged in, it seems you  
store your session (or at least your login-info) inside the client-  
side cookies (see cookiestore). if in doubt check your cookies for  
e.g. with firebug/firecookie.

for automatical timeout and removal put the following in your  
application controller:

# session-timeout after inactivity of one hour.

MAX\_SESSION\_PERIOD = 1800

before\_filter :session\_expiry

# checks and (re-)calculates expiry time for sessions

def session\_expiry  
# if there is a session[:expiry\_time], check it  
reset\_session if session[:expiry\_time] and session[:expiry\_time] \<  
Time.now  
# reset expiry\_time  
session[:expiry\_time] = MAX\_SESSION\_PERIOD.seconds.from\_now  
return true  
end

---

<div class="post-metadata">

**Author:** ![sa125](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b4bc9f/32.png) [@sa125](https://www.ruby-forum.com/u/sa125)\
**Post date:** [February 25, 2009, 11:35am UTC](https://www.ruby-forum.com/t/authentication-and-user-management-questions/161306/3 "2009-02-25T11:35:47Z")

</div>

MaD wrote:

> for your permissions problem I’d suggest the implementation of roles  
> or groups. that way you can add users to groups or give them roles,  
> which can be checked in a before\_filter in your controllers.

I thought about creating groups, but then won’t this complicate things?  
I’ll have group\_pages table, and how do I manage those? can a user  
belongs to many groups?

> for your permissions problem I’d suggest the implementation of roles  
> or groups. that way you can add users to groups or give them roles,  
> which can be checked in a before\_filter in your controllers.
> 
> sessions:  
> if you are using activerecordstore (and thus your sessions are saved  
> in a db-table) deleting those entries should result in a logout. there  
> should be configuration in your environment like this:  
> config.action\_controller.session\_store = :active\_record\_store

after commenting the above line, I got an InvalidAuthentictyToken error,  
which probably comes from my login form. This is how my view looks now:

\<% form\_for :user do |f| %\>

user: \<%= f.text\_field :user\_name %\>

pass: \<%= f.password\_field :password %\>

 \<%= f.submit 'login' %\> \<% end %\>

I checked the markup and I can see the hidden field containing the  
authenticity token… So I’m not sure why this messes up.

Before these changes I had this view:

user: \<%= text\_field\_tag :user\_name, params[:user\_name] %\>

pass: \<%= password\_field\_tag :password, params[:password] %\>

\<%= submit\_tag 'login' %\>

And things worked (except that the sessions weren’t saved in the  
database). Help?..

---

<div class="post-metadata">

**Author:** ![sa125](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b4bc9f/32.png) [@sa125](https://www.ruby-forum.com/u/sa125)\
**Post date:** [February 25, 2009, 3:08pm UTC](https://www.ruby-forum.com/t/authentication-and-user-management-questions/161306/4 "2009-02-25T15:08:19Z")

</div>

> I thought about creating groups, but then won’t this complicate things?  
> I’ll have group\_pages table, and how do I manage those? can a user  
> belongs to many groups?

it’s actually best to create a many-to-many relationship (user habtm  
groups).  
there are many plugins outthere that provide just what you need. if  
you don’t want to just use one of these (either a complete  
authentication-plugin or just something like acts\_as\_role), you could  
still take a look at them for inspiration.

> > config.action\_controller.session\_store = :active\_record\_store  
> > after commenting the above line, I got an InvalidAuthentictyToken error,  
> > which probably comes from my login form.

just to make sure: you are using active\_record\_store now, right?

> I checked the markup and I can see the hidden field containing the  
> authenticity token… So I’m not sure why this messes up.

try to delete your browser’s cookies and cache as well as your session  
table. maybe you have a conflict with one of the old sessions/cookies.

additionally check that you have the following:

# environment.rb:

config.action\_controller.session = {  
:session\_key =\> ‘\_myapp\_session’,  
:secret =\> ‘secretpass’ # use a long and good secret!  
}

config.action\_controller.session\_store = :active\_record\_store

# application.rb

protect\_from\_forgery :secret =\> ‘secretpass’

that should do it.

---

<div class="post-metadata">

**Author:** ![sa125](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b4bc9f/32.png) [@sa125](https://www.ruby-forum.com/u/sa125)\
**Post date:** [February 27, 2009, 7:09am UTC](https://www.ruby-forum.com/t/authentication-and-user-management-questions/161306/5 "2009-02-27T07:09:20Z")

</div>

It seems the problem stemmed from the session\_expiry check:

> for automatical timeout and removal put the following in your  
> application controller:
> 
> # session-timeout after inactivity of one hour.
> 
> MAX\_SESSION\_PERIOD = 1800
> 
> before\_filter :session\_expiry #####\<-- this was the problem
> 
> # checks and (re-)calculates expiry time for sessions
> 
> def session\_expiry  
> # if there is a session[:expiry\_time], check it  
> reset\_session if session[:expiry\_time] and session[:expiry\_time] \<  
> Time.now  
> # reset expiry\_time  
> session[:expiry\_time] = MAX\_SESSION\_PERIOD.seconds.from\_now  
> return true  
> end

Although I used 1800 seconds, it reset the session before I logged in,  
rendering the authenticity token invalid. Removing that before filter  
solved that. I’ll have to keep looking into the whole auto-logout thing  
🙂

Thanks!

---

<div class="post-metadata">

**Author:** ![sa125](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b4bc9f/32.png) [@sa125](https://www.ruby-forum.com/u/sa125)\
**Post date:** [February 26, 2009, 9:46am UTC](https://www.ruby-forum.com/t/authentication-and-user-management-questions/161306/6 "2009-02-26T09:46:08Z")

</div>

> just to make sure: you are using active\_record\_store now, right?

Yeah.

> try to delete your browser’s cookies and cache as well as your session  
> table. maybe you have a conflict with one of the old sessions/cookies.

Deleted all cookies, cache and authenticated sessions (in firefox -  
Ctrl+Shift+Del).

> additionally check that you have the following:
> 
> # environment.rb:
> 
> config.action\_controller.session = {  
> :session\_key =\> ‘\_myapp\_session’,  
> :secret =\> ‘secretpass’ # use a long and good secret!  
> }

Definitely have all those.

> config.action\_controller.session\_store = :active\_record\_store
> 
> # application.rb
> 
> protect\_from\_forgery :secret =\> ‘secretpass’

Yup, that too.

When I submit the login form, I get the error screen and the request  
parameters are showing that an authenticity token is submitted:

{“commit” =\> “login”  
“authenticty\_token” =\> “bnadsas9dadasd09as8931012kjk12301i23”,  
“user” =\> { “user\_name” =\> “newbie”,  
“password” =\> “topsecret” } }

So I don’t know where the token comes from if it doesn’t match the one  
submitted - all sessions, cookies and cache were cleared.

Again, my login form looks like this:

\<% form\_for :user, :url =\> { :action =\> ‘do\_login’ } do |f| %\>

user: \<%= f.text\_field :user\_name %\>

pass: \<%= f.password\_field :password %\>

 \<%= f.submit 'login' %\> \<% end %\>

My do\_login action is this:

def do\_login  
if request.post?  
user = User.authenticate(params[:user\_name], params[:password])  
if user  
session[:user\_id] = user.id  
uri = session[:original\_uri]  
session[:original\_uri] = nil  
redirect\_to uri || home\_page  
else  
flash.now[:notice] = “Invalid user/password - please try again”  
end  
end  
end

I should mention that in my application controller I have:

before\_filter :authorize, :except =\> :do\_login

def authorize  
unless User.find\_by\_id(session[:user\_id])  
session[:original\_uri] = request.url  
flash[:notice] = “please log in”  
redirect\_to :controller =\> ‘login’, :action =\> ‘do\_login’  
end  
end

---

<div class="post-metadata">

**Author:** ![sa125](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b4bc9f/32.png) [@sa125](https://www.ruby-forum.com/u/sa125)\
**Post date:** [March 3, 2009, 8:54am UTC](https://www.ruby-forum.com/t/authentication-and-user-management-questions/161306/7 "2009-03-03T08:54:47Z")

</div>

MaD wrote:

> at least that token-problem is solved.
> 
> but it’s still weird, cause that session\_expiry code is actually  
> working on one of my apps. are you sure you don’t have some sort of  
> typo? (sth. like \> instead of \<) i would debug that piece of code to  
> see, why the session is reset.  
> btw: 1800 sec is of course half an hour (not what my comment stated)  
> _g_

My code seems intact -

MAX\_SESSION\_PERIOD = 1800  
before\_filter :check\_session\_expiration

def check\_session\_expiration  
if session[:expiry\_time] and seesion[:expiry\_time] \> Time.now  
reset\_session  
end

session[:expiry\_time] = MAX\_SESSION\_PERIOD.seconds.from\_now  
return true  
end

I’m not really sure what about it messes things up - on the surface it  
seems as though it should work. For now I’ll omit it and try to  
gradually introduce it.

Regarding my previous question on using groups and users - I decided to  
go with users that can only belong to a single group - this makes it  
easier to manage on my end, and there really is no need to add the  
many-to-many groups/users at this point.

Say that I have many groups (10 or so) and each group has varying  
permissions on pages across the site. I also created a page and  
permission models, such that:

page has\_and\_belongs\_to\_many :groups, :join\_table =\> ‘permissions’  
group has\_and\_belongs\_to\_many :pages, :join\_table =\> ‘permissions’

The permissions table holds the page\_id and group\_id, and booleans for  
can\_read, can\_write and can\_execute.

My question is - what’s the best way to manage these permissions in my  
controllers? I thought about adding an if statement at the beginning of  
each action to see if the user’s group can access this page, but this  
seems like a lot of duplication:

def index  
if user.group.can\_access\_page?(page\_id)  
# render index  
else  
# render some ‘you cannot access this page’ message  
end  
end

def update  
if user.group.can\_write\_page?(page\_id)

# perform update

else

# render ‘sorry - no updates allowed’

end  
end

and so on. I could just restrict access to the controller with before  
filter, but what if the user uses direct routes in the address bar  
(/controller/new/1)?

I’d appreciate insights on this - I really want to dry up my code as  
much as possible - thanks.

---

<div class="post-metadata">

**Author:** ![sa125](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b4bc9f/32.png) [@sa125](https://www.ruby-forum.com/u/sa125)\
**Post date:** [February 27, 2009, 10:38am UTC](https://www.ruby-forum.com/t/authentication-and-user-management-questions/161306/8 "2009-02-27T10:38:54Z")

</div>

at least that token-problem is solved.

but it’s still weird, cause that session\_expiry code is actually  
working on one of my apps. are you sure you don’t have some sort of  
typo? (sth. like \> instead of \<) i would debug that piece of code to  
see, why the session is reset.  
btw: 1800 sec is of course half an hour (not what my comment stated)  
_g_
