[Seaside] Seaside login - a write up
Roger Whitney
whitney at cs.sdsu.edu
Mon Sep 27 22:43:52 CEST 2004
I wrote the following for students on how to have users login to access=20=
Seaside. We are using the VW version of Seaside. I thought I would post=20=
the write up to make sure that I did not miss anything that I should=20
cover.
Part of what is below is based on an earlier post by Michal. (I do not=20=
know his last name.)
---------- Seaside Login---------
There are times when we need to have users log in. We can do this in=20
two ways:
=B7 Use built-in authentication system
=B7 Create our own authentication system
----------Using Built-in Authentication system
To use the built-in authentication system add one of the following=20
class methods (not instance methods) to your component class. The=20
built-in system uses the standard http authentication scheme.
The first method when run will prompt you to set a user name and=20
password, that the user will have to enter to access your component.=20
Before you can access the web application you need to enter those. This=20=
method is used by the Seaside config page.
initialize
"self initialize"
(self registerAsAuthenticatedApplication: =
'standardAuthentication')
The second method allows you to specify the username and password in=20=
code. It just makes explicit what registerAsAuthenticatedApplication:=20
does. The class method initialize is called automatically when a class=20=
is loaded from a file or parcel/package. You may not want the user=20
prompted at that time =D0 for example when you are installing a headless=20=
server. In that case you might wish to have the initialize method call=20=
the method below.
initializeUser: aName password: aString
"self initializeUser: 'Foo' password: 'bar' "
| application |
application :=3D
self registerAsApplication: 'standardAuthentication'.
application configuration
addAncestor: WAAuthConfiguration localConfiguration.
=09
application preferenceAt: #login put: aName.
application preferenceAt: #password put: aString.
=09
^ application
---------- Modifying the Existing System
The problem with the previous methods is that you only have one user=20
and one password. We may need to support many different users. We can=20
modify the existing system to use our class to validate usernames and=20
passwords, thus allowing multiple users and passwords.
Create a subclass of WAAuthConfiguration with the method mainClass.=20
This method just returns the class to use to validate usernames and=20
passwords. (Note using the Seaside configuration pages one can avoid=20
the need for this class.)
Smalltalk.Seaside defineClass: #CS683AuthConfiguration
superclass: #{Seaside.WAAuthConfiguration}
instanceVariableNames: ''
classInstanceVariableNames: ''
Instance Method
mainClass
^ CS683AuthMain
Then we need the authorization class. It needs one method=20
verifyPassword:forUser:. This method returns true or false depending on=20=
if the username & password are correct. The example here only has one=20
username & password. However the could for example open a file and read=20=
a list of usernames & passwords.
Smalltalk.Seaside defineClass: #CS683AuthMain
superclass: #{Seaside.WAAuthMain}
instanceVariableNames: ''
classInstanceVariableNames: ''
Instance Method
verifyPassword: password forUser: username
^'foo' =3D username and: ['bar' =3D password]
Now in your WAComponent subclass and the following class method and=20
use it to registration your class.
YourComponent Class>>initialize
"self initialize"
| application |
application :=3D self registerAsApplication: myApp.
application configuration
addAncestor: CS683AuthConfiguration localConfiguration.
^ application
Now when anyone accesses the component they will be required to give a=20=
username and password. They will be required to do this only once per=20
session.
Note that the class CS683AuthConfiguration and the configuration in the=20=
above method can be replaced by using the configuration page.
----------Your own Password System
There are some situations where the above solutions are adequate. We=20
may need:
=B7 Know who login in
=B7 Provide more information on the login page
=B7 Only parts of application are password protected
The following is based on a post to seaside mailing list by Michal. The=20=
following class implements a login page.
Smalltalk.Seaside defineClass: #SeasideLogin
superclass: #{Seaside.WAComponent}
instanceVariableNames: 'username password '
classInstanceVariableNames: ''
Instance Methods
password
^password ifNil: [''].
password: aString
^password :=3D aString
username
^username ifNil: [''].
username: aString
^username :=3D aString
renderContentOn: html
html attributeAt: 'align' put: 'center'.
html form:
[(html attributes)
align: 'center';
cellspacing: '10'.
html table:
[html tableRowWith: 'Username'
with: [html textInputOn: =
#username of: self].
html tableRowWith: 'Password: '
with: [html textInputOn: =
#password of: self]].
html
break;
submitButtonWithAction: [self =
handleLogin]]
handleLogin
self username =3D 'Bar' ifFalse:[^self].
self password =3D 'foo' ifFalse:[^self].
self answer: username.
The above method only handles one user, but can be modified to handle=20
more.
Using SeasideLogin
One can now use SeasideLogin in another component. Once can use it with=20=
a task or use it in a session. We will look at the later.
---------- Session & Login
We can have a user login only once per session. To do this create a=20
subclass of WASession with the following two methods.
Smalltalk.Seaside defineClass: #CS683Session
superclass: #{Seaside.WASession}
instanceVariableNames: 'user '
classInstanceVariableNames: ''
Instance Methods
loginUser
^user :=3D self mainClass new call: SeasideLogin new
user
user ifNil: [self loginUser].
^user
----------Configuring the Component to use CS683Session
Now given a component must be configured to use the new session. One=20
way to do this is to via the configuration page for the component. When=20=
you configure a component toward the bottom of the page you will see a=20=
line starting with Session class.
On that line click on override. Once you have done this you will be=20
given a list of which type of session to use with the component. Select=20=
CS683.
----------Insuring the User has Logged in
Now in your component to insure the user has logged in and to get the=20
user name in your component use:
self session user.
If the user has not logged in they will be sent to the login page. If=20
they already have logged in during that session you will just get the=20
user name.
---------- Making the User Login First
If you want to make the user login in before anything else happens you=20=
can call self session user in your renderContentOn: method
renderContentOn: html
user :=3D self session user.
Etc.
----------Automatic Login
You can force the user to login before accessing the component=20
automatically by adding the following method to the CS683Session class
CS683Session>> start: aRequest
self loginUser.
^super start: aRequest
Before any component is displayed during that session, the login page=20
is displayed.
---------- What not to do
One might be tempted to avoid the overhead of using a session by doing:
MyComponent>> renderContentOn: html
user :=3D self call: SeasideLogin new.
Rest of your renderContentOn: code.
At least in the VW version of Seaside, doing this makes the application=20=
unstable, so don=D5t do it.
More information about the Seaside
mailing list