[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