B4J Tutorial [Server] Login System & Filters Tutorial

upload_2014-3-19_16-8-41.png

Try it online: https://www.b4x.com:51042/login_example/
Note that it is not connected to the forum database. Feel free to test it and register new users. Its only purpose is to demonstrate this solution.

Login Example

A typical web solution consists of several folders. In this case the structure is:

42fm.png


We want to restrict access to files and handlers under the 'members' folder to registered members only.

This is done with a Filter.

Filters

Each request is handled by a single handler or if no handler matches the URL then a file is returned (or 404 error if there is no matching file).

Filters are similar to handlers. However the request can go through any number of filters before it reaches its final destination. Filters can change the request destination or block the request.

A Filter class should include a sub named Filter with the following signature:
B4X:
Public Sub Filter(req As ServletRequest, resp As ServletResponse) As Boolean
If the filter sub returns True then the request will continue to the next filter or final destination, otherwise the request completes and the response is committed.

Adding filters is done with Server.AddFilter. In our example we want to apply the filter to all files and handlers under the 'members' folder (notice the wildcard in the path):
B4X:
srvr.AddFilter("/login_example/members/*", "MembersFilter", False)

The filter code:
B4X:
Public Sub Filter(req As ServletRequest, resp As ServletResponse) As Boolean
   If req.GetSession.GetAttribute2("registered", "") = True Then
     'check that no more than 30 minutes passed since last activity
     If req.GetSession.LastAccessedTime + DateTime.TicksPerMinute * 30 > DateTime.Now Then
       Return True 'allow request to continue
     End If
   End If
   resp.SendRedirect("/login_example/")
   Return False
End Sub
In this code we check whether the user session includes an attribute named 'registered' with the value of True. If not then the response is redirected to the login page.

This attribute is set when the user registers to the forum or signs in. Remember that user sessions are stored in the server memory. This means that they are safe to use (a cookie will not work here). However this also means that the user will need to sign in again (no need to register again) if the server is restarted.

Passwords

When a user registers we need to save it in the database. For security reasons we do not save the password. Instead we save a hash of the password combined with a "salt" value. When the user signs in we do the same process and check whether the current hash equals to the stored hash.

Captcha

Google ReCaptcha service is used to make sure that a human is registering and not a bot. In order to use this service you need to create a key: https://www.google.com/recaptcha/admin/create
You will receive two keys. The public key should be set in the JavaScript code (in login_example/index.html) and the private key should be set in the settings file.

Note the usage of StartMessageLoop / StopMessageLoop in LoginHelper. These methods block the thread while it waits for the JobDone event.

Log out

The Logout handler is quite simple. It invalidates the user session. This means that the next time the user tries access a resource under 'members' folder they will be redirected to the login page.

Tips

- All the settings are saved in a file named settings.txt. This makes it simple to test the project locally and then update it on the server without overwriting the server settings file. I'm using Wamp to test it locally with MySQL database.
- Use #MergeLibraries: False. This way you can update the server jar without uploading a large jar file each time. You will need to manually upload the libraries once.
- I'm using this command to run it on the Linux server
B4X:
nohup ../jre1.7.0_51/bin/java -jar ServerExample.jar > nohup.out &
- The project depends on the following B4A libraries: ByteConverter and Encryption
 

Attachments

  • LoginExample.zip
    11.7 KB · Views: 2,184
Last edited:

Claudio Oliveira

Active Member
Licensed User
Longtime User
Hi Erel

The statement "srvr.AddFilter("/login_example/members/*", "MembersFilter", False)" is giving me the following error:

Parsing code. 0.00
Compiling code. Error
Error compiling program.
Error description: Unknown member: addfilter
Occurred on line: 22
srvr.AddFilter("/login_example/members/*", "MembersFilter", False)
Word: addfilter


B4J-1.80 Beta
jServer-1.20
 

AscySoft

Active Member
Licensed User
Longtime User
I want to use this code to secure my custom web server. A question. Suppose that the log in page is the first page served by the server (index.html in the www folder). But what if the user try to bypass it by typing into the browser an address who point to ... say reports. How can I automatically redirect him to the log in page first? Is it by setting a global variable and filter it in every class/handler in my server?
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
<<Is it by setting a global variable and filter it in every class/handler in my server?>>
No.

You should let the filter process all requests:
B4X:
srvr.AddFilter("/*", "MembersFilter", False)
However you should make sure to allow the "login page" to show. Otherwise you will create an endless redirection loop.

It might be simpler to create a members only folder and move all the examples under that folder. This way you will have a public place to put all the resources.
 

AscySoft

Active Member
Licensed User
Longtime User
Let's say I would like the idea of filtering all the requests. How should I modify this. Is this correct:
B4X:
If req.GetSession.GetAttribute2("registered", "") = True Or req.FullRequestURI.Contains("login page") Then
    'check that no more than 30 minutes passed since last activity
    If req.GetSession.LastAccessedTime + DateTime.TicksPerMinute * 30 > DateTime.Now Then
      Return True 'allow request to continue
    End If
  End If
to allow only "login page" to show in first place?
 

LucaMs

Expert
Licensed User
Longtime User
You have used hashing to protect passwords;
but if I did not follow bad the example, them are saved "hashed" (?) in the db, as if it was not safe, while from browser to server it is clear.

"www" is the server's default folder (the folder whose content is accessible)?
In the example "B4J Tutorials - [Server] Building web servers with B4J" you use:
B4X:
srvr.StaticFilesFolder = File.Combine(File.DirApp, "www")
here not.

Thanks
 
Last edited:

tuicemen

Member
Licensed User
Longtime User
while trying to load this example I get a pop up the following libraries are missing:
byteconverter
encryption
Where do I find these?
 
Top