How to handle web application login

R

Ryan Stewart

I'm wondering how you out there who work with web applications handle
user login. The common practice where I am has always been to stick a
User object in the session:
session.setAttribute("currentUser", user);

I'm becoming less and less satisfied with that method. It seems very
cluttered and not very object oriented. Anywhere that we want to check
if someone is logged in, it's:
if (session.getAttribute("currentUser") != null) {
....
}

Or worse, if we want to do something with a user *if* he or she is
logged in:
User user = (User) session.getAttribute("currentUser");
if (user != null) {
....
} else {
....
}

First, I don't like having to know about the "currentUser" key. That
should be hidden away somewhere safe where other developers working on
or maintaining the project don't have to know about it if they don't
want to. Also, the "log a user in" and "is a user logged in?" processes
seem to be behavior, which, under the guidelines of OO design, should
be methods. Not writing them as methods seems to me to promote
procedural programming in a place where the code can already get quite
complex.

One possible solution would be something like this in the User class
(as a minimal implementation):
public void login(HttpSession session) {
session.setAttribute("currentUser", this);
}

public User getUser(HttpSession session) {
return (User) session.getAttribute("currentUser");
}

Or possibly put that in a utility class of some sort. Then it becomes
part of the User (or whatever) interface, easily documented and
understood, and the implementation is hidden, as I feel it should be.
Whatever the case, you run into the MVC argument. User (or a utility
class) is Model. HttpSession is more to the Controller side. The two
shouldn't interact in this way in some people's opinions.

I know there's something wrong here, but I haven't quite figured out
what to do yet. Does anyone else have insight on this or know where to
find some best practices?
 
J

John C. Bollinger

Ryan said:
I'm wondering how you out there who work with web applications handle
user login. The common practice where I am has always been to stick a
User object in the session:
session.setAttribute("currentUser", user);

There are three general possibilities:

(1) Put some object in the session to indicate that a user is logged in.
It is often convenient for the object to be one that describes the
user, but the key point is that the attribute name is a "well known" one
reserved for the application to use for this purpose.

(2) Record user login information in a separate repository, such as a
map or DB, then use some characteristic of the session, for instance the
ID, to reference this data.

(3) Use the servlet API's built-in security mechanisms.
I'm becoming less and less satisfied with that method. It seems very
cluttered and not very object oriented. Anywhere that we want to check
if someone is logged in, it's:
if (session.getAttribute("currentUser") != null) {
...
}

Or worse, if we want to do something with a user *if* he or she is
logged in:
User user = (User) session.getAttribute("currentUser");
if (user != null) {
...
} else {
...
}

First, I don't like having to know about the "currentUser" key. That
should be hidden away somewhere safe where other developers working on
or maintaining the project don't have to know about it if they don't
want to. Also, the "log a user in" and "is a user logged in?" processes
seem to be behavior, which, under the guidelines of OO design, should
be methods. Not writing them as methods seems to me to promote
procedural programming in a place where the code can already get quite
complex.

You are not complaining about the login procedure or even the storage of
login info, but rather about lack of a good abstraction for handling
login info. If the servlet API's built-in facilities are insufficient
then the next simplest solution is to provide your own mechanism, as you
go on to discuss.
One possible solution would be something like this in the User class
(as a minimal implementation):
public void login(HttpSession session) {
session.setAttribute("currentUser", this);
}

public User getUser(HttpSession session) {
return (User) session.getAttribute("currentUser");
}

Or possibly put that in a utility class of some sort. Then it becomes
part of the User (or whatever) interface,

Hold up. Putting it in a utility class does not make it part of the
User interface.
easily documented and
understood, and the implementation is hidden, as I feel it should be.
Whatever the case, you run into the MVC argument. User (or a utility
class) is Model. HttpSession is more to the Controller side. The two
shouldn't interact in this way in some people's opinions.

A utility class is not Model, at least not generally. By its nature it
tends more toward the controller side itself. Or toward business logic,
if you prefer to draw the distinction that way.
I know there's something wrong here, but I haven't quite figured out
what to do yet. Does anyone else have insight on this or know where to
find some best practices?

I don't know about best practices per se, but I agree that you ought to
encapsulate the login and user information functions. It would probably
be appropriate to define a class that handles the details, and you may
find that this is a good home for authorization decision-making as well.
I helped design a web application that works in this way.


John Bollinger
(e-mail address removed)
 
R

Ryan Stewart

John C. Bollinger said:
There are three general possibilities:

(1) Put some object in the session to indicate that a user is logged in.
It is often convenient for the object to be one that describes the user,
but the key point is that the attribute name is a "well known" one
reserved for the application to use for this purpose.
Same problem as putting the user in the session. What interacts with the
session?
(2) Record user login information in a separate repository, such as a map
or DB, then use some characteristic of the session, for instance the ID,
to reference this data.
I've considered something like this, but there must again be some
interaction with the session.
(3) Use the servlet API's built-in security mechanisms.
I'd like to, but for the moment we must maintain platform independence, and
as far as I'm aware, each container provides its own implementation of
security.
You are not complaining about the login procedure or even the storage of
login info, but rather about lack of a good abstraction for handling login
info.
Yes, exactly.
Hold up. Putting it in a utility class does not make it part of the User
interface.
That's what the "(or whatever)" was for. I meant that the login and getUser
methods and possibly others could be put into a User class or some utility
class and become a part of whichever class' established interface that they
are in. Sorry for the abbreviated sentence.
A utility class is not Model, at least not generally. By its nature it
tends more toward the controller side itself. Or toward business logic,
if you prefer to draw the distinction that way.
I would tend toward the controller idea somewhat, but not everybody would
agree. And in general don't you think that business logic == Model?
I don't know about best practices per se, but I agree that you ought to
encapsulate the login and user information functions. It would probably
be appropriate to define a class that handles the details, and you may
find that this is a good home for authorization decision-making as well.
This is what I'm looking around for.
I helped design a web application that works in this way.
Are you able/willing to give a quick sketch of how it worked?
 
A

AlexKay

Hi,
Or possibly put that in a utility class of some sort. Then it becomes
part of the User (or whatever) interface, easily documented and
understood, and the implementation is hidden, as I feel it should be.

I agree having a separate "User" class does tidy everything up. User is
pure model stuff, so removing it from your view is good.

Mind you, a view can *query* the model with something like
....isUserLoggedIn(...) ? but it should not get involved in
implementing model details like all that get/set "currentUser" stuff.

Your thinking and approach sounds good to me.
Whatever the case, you run into the MVC argument. User (or a utility
class) is Model. HttpSession is more to the Controller side. The two
shouldn't interact in this way in some people's opinions.

HttpSession is not really dedicated to "Controller", it is part of the
(infrastructure) model.

It is very common for a model to utilize external classes like
database, network services or whatever else. There is nothing wrong in
having User use HttpSession or data access classes.

... you run into the MVC argument ...
I'm not sure which MVC argument you're running into, because there are
in fact many varients. Most modern MVC implementations are not like the
original 80's Smalltalk version.

Yes they share the main intent, which is simply to separate model and
view but then differ widely on the details of all else in particular in
relation to the controller.

Simply:-
User.displayWithFancyColors () is bad, the model has view stuff in it.
Conversely
aView.jsp filled with get/set 'currentUser' can be improved by removing
the model stuff. Just as you suggested.

HTH,
Alex
 
J

John C. Bollinger

Ryan said:
Same problem as putting the user in the session. What interacts with the
session?

You're quite right, but whatever interacts with the session has to get
its data from some place. Putting an object in the session with a
well-known attribute name may be a suitable part of the solution.
I've considered something like this, but there must again be some
interaction with the session.

As above.
I'd like to, but for the moment we must maintain platform independence, and
as far as I'm aware, each container provides its own implementation of
security.

That's not quite how I'd describe it. The servlet API's built-in
mechanism is based on declarative security statements in the web
application's deployment descriptor. Four different mechanisms are
defined for collecting authentication information from the client, and
there are a few programmatic interfaces for extracting some of the
security information within the webapp. All of that is part of the spec.

What varies from container to container is the mechanism for verifying
login credentials and mapping users and groups to roles. This may still
be more container dependence than you would like, however.
I would tend toward the controller idea somewhat, but not everybody would
agree. And in general don't you think that business logic == Model?

No I don't. To the incomplete extent that they are parallel, model /
view / controller matches up best with persistence / presentation /
business logic, respectively.
This is what I'm looking around for.



Are you able/willing to give a quick sketch of how it worked?

The view portion of the application is JSP-based. We created an
"AuthenticationController" class (which turned out to not be an ideal
name) which we bound to each page as a JavaBean with session scope and
well-known name. We put the details of the <jsp:useBean> (and a few
other common details) into a JSP fragment that all the pages
<@include>ed. Each session thus has its own AuthenticationController
instance (regardless of whether or not the user had logged in), and this
object provides methods for both authentication and authorization logic.
After login the session's AuthenticationController maintains user
information internally, instead of storing it as a separate object in
the session. We used scriptlet code to invoke the
AuthenticationController's methods, but the whole binding and method
invocation business could easily be wrapped up in custom tags.

Hope that helps.


John Bollinger
(e-mail address removed)
 
R

Ryan Stewart

[...]
What varies from container to container is the mechanism for verifying
login credentials and mapping users and groups to roles. This may still
be more container dependence than you would like, however.
It means that I can't write an application using Tomcat as a development
environment, then WAR up the application and deploy it immediately to an
Oracle server.

[...]
No I don't. To the incomplete extent that they are parallel, model / view
/ controller matches up best with persistence / presentation / business
logic, respectively.
Wow, I don't think I've heard that one before. Granted I've not read up too
much on MVC in general.
[...]
Thanks for the thoughtful replies and the information. I think it will be
helpful.
 
R

Ryan Stewart

AlexKay said:
I agree having a separate "User" class does tidy everything up. User is
pure model stuff, so removing it from your view is good.

Mind you, a view can *query* the model with something like
...isUserLoggedIn(...) ? but it should not get involved in
implementing model details like all that get/set "currentUser" stuff.

Your thinking and approach sounds good to me.
Right, I'm not worried about mixing User stuff into the view. It's how much
coupling should there be between User and javax.servlet.http package (for
example).
HttpSession is not really dedicated to "Controller", it is part of the
(infrastructure) model.

It is very common for a model to utilize external classes like
database, network services or whatever else. There is nothing wrong in
having User use HttpSession or data access classes.
Good, this is what I'm looking for :)
I'm not sure which MVC argument you're running into, because there are
in fact many varients. Most modern MVC implementations are not like the
original 80's Smalltalk version.

Yes they share the main intent, which is simply to separate model and
view but then differ widely on the details of all else in particular in
relation to the controller.

Simply:-
User.displayWithFancyColors () is bad, the model has view stuff in it.
Conversely
aView.jsp filled with get/set 'currentUser' can be improved by removing
the model stuff. Just as you suggested.
What I'm running into is a mindset that no classes we write like User or
other "business logic" should have any reference to anything in the
javax.servlet.http package. When I first suggested it, people looked at me
like I had just turned purple with red polka dots or something.

To add some information, we are using Struts for this project. The argument
is that javax.servlet.http classes should only be used in Actions, as they
are part of the controller and that's where those classes belong.
 
C

Chris Uppal

Ryan said:
Or worse, if we want to do something with a user *if* he or she is
logged in:
User user = (User) session.getAttribute("currentUser");
if (user != null) {
...
} else {
...
}

Just a small suggestion, but if you introduce a notion of "guest user" or
similar, then you can avoid some of these ugly conditionals. The idea is that
a session /always/ has a "currentUser", but that varies polymorphically between
a (limited) GuestUser and a (less limited) ValidatedUser.

-- chris
 
A

AlexKay

Ryan said:
Right, I'm not worried about mixing User stuff into the view.

By 'mix' I hope you mean the view will only *query* the model and not
actually *implement* any model code?

A complete separation of model and view is the main intent of patterns
like MVC. No view calls from models. And no model implementations in
views, but views can just call or query models.
It's how much
coupling should there be between User and javax.servlet.http package (for
example).

It's an engineering tradeoff. Extra decoupling comes at extra cost,
namely more code. Why pay the price if it buys you something you don't
need?

If User is used as part of a complex model in say both web and Swing
apps than certainly it should not be coupled exclusively to the servlet
api.

If User is used only in web apps then it may be the "simplest thing
that will work", and so a valuable idea.
Good, this is what I'm looking for :)

What I'm running into is a mindset that no classes we write like User or
other "business logic" should have any reference to anything in the
javax.servlet.http package. When I first suggested it, people looked at me
like I had just turned purple with red polka dots or something.

It's a case of "you can run but you can't hide" something somewhere
must keep state across requests in relation to Users and the
logged-in-edness state.

The controller should *not* keep state, that is the model's job.

And if the model doesn't use the servlet session scope vars then what
will you use?

And if you write code in a JSP to model a user than you've put model
code into a view or Java code into a JSP, a place where code don't
belong.

If you only ever model "logged-in" and "not-logged-in" then that small
amount of code in the JSP won't seem so bad. But if a User can later
have preferrences, defaults, userLevels, wishLists, lastItemsBrowsed
etc, it'll all start to look out of place rather badly.
To add some information, we are using Struts for this project. The argument
is that javax.servlet.http classes should only be used in Actions, as they
are part of the controller and that's where those classes belong.

javax.servlet.http is not exclusively part of the controller at all.

The main job of the controller is to handle imputs, so yes things like
request.getParameter are controller material. But the API is much
broader than that. Things like get/set attributes can be used by the
model, controller, view, or application in general.

Session variables are after all one of Sun's solutions to the
HTTP-statelessness problem. State is a model not controller issue.

But if your model must avoid that offering what will you use to capture
that state? A file, a database, cookies, Java code in a jsp, or an ejb?


Frankly I think you'll find session variables are great for modelling
session stuff. Driving all that from a JSP will work for simple model
stuff but will break down bady if User gets more interesting.
Cheers
Alex Kay
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top