In Chapter 12 of my Seaside Tutorial I give an example of rendering different content for a web site based on whether the user is known or not. This allows you to provide a public view (for un-authenticated users) and appropriate private views (for authenticated users), but requires you to to manage your own login dialog.

Seaside has the built-in ability to use HTTP Authentication to restrict an application to a specific user/password. The method WAAdmin class>>#’register:asApplicationAt:user:password:’ registers the application with WAAuthenticationFilter as a filter and provides a single user and password that must be provided in order to view the initial page. This provides some password security, but does not differentiate among allowed users (e.g., everyone will use the same ‘admin’ user name).

If you have an application that will always require authentication but should differentiate among multiple users, you can use WAAuthenticationFilter as well. For example, if you have a subclass of WAComponent named HelloComponent, you could provide a class-side initialization method as follows:

initialize
"HelloComponent initialize."
 | application filter |
 application := WAAdmin 
 register: self
 asApplicationAt: 'hello'.
 filter := WAAuthenticationFilter new
 authenticator: self;
 yourself.
 application addFilter: filter.

Like Seaside’s default authentication approach, this method adds a WAAuthenticationFilter as a filter, but provides an override to the default authenticator (here the component class itself). The authenticator must implement #’verifyPassword:forUser:’. The class side of HelloComponent could have something more sophisticated than the following:

verifyPassword: password forUser: username
 username = 'bert' ifTrue: [^password = 'ernie'].
 ^false.

At this point your render code can assume that a valid user has been properly authenticated and can vary the content based on the user. For example, the following instance-side method in HelloComponent would show what user was authenticated:

renderContentOn: html
 html text: 'Hello ' , self requestContext request user , '!'.

Now you have basic HTTP authentication for multiple users. Of course, you are now subject to the limitations of basic HTTP authentication, including the fact that logout is somewhat awkward. You can provide a logout link:

renderContentOn: html
 html text: 'Hello ' , self requestContext request user , '!'; break.
 html anchor
 callback: [self doLogout];
 with: 'Logout'.

The logout method informs the user how to complete the logout and then adds a field to let the verification method know to fail:

doLogout
	| url |
	self inform: 'When the login dialog appears, click the Cancel button then close your browser.'.
	url := self requestContext request url copy.
	url addField: 'logout'.
	self requestContext redirectTo: url.

The verification method would then check for the new field:

verifyPassword: password forUser: username
 (WACurrentRequestContext value request url queryFields includesKey: 'logout') ifTrue: [^false].
 username = 'bert' ifTrue: [^password = 'ernie'].
 ^false.

Charlie Meyer has an explanation of how he used a similar approach with LDAP authentication.

Advertisements