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: 1,815
Last edited:

moster67

Expert
Licensed User
can you change the code and add the new ReCaptcha

Thought I would add an example of using the reCAPTCHA V.2 here since it is related to the sample-app posted by Erel. The old reCAPTCHA did not work for me.

Below procedure for implementing reCAPTCHA V.2 worked for me:

upload_2017-12-18_22-32-56.png


1) first sign up for an api-key for your site (selecting reCAPTCHA V2)
http://www.google.com/recaptcha/admin

2) Modify the index.html file in the login_example directory by removing the old lines referring to reCAPTCHA V.1. Then paste this snippet before the closing </head> tag on your HTML template:
B4X:
<script src='https://www.google.com/recaptcha/api.js'></script>
In the same file, paste this snippet at the end of the <form> where you want the reCAPTCHA widget to appear:
B4X:
<div class="g-recaptcha" data-sitekey="Your Site api-key"></div>
3) In the settings.txt file, add your secret api-key: keyRecaptchaPrivateKey=secret api-key

In the B4J ServerExample project, open the RegisterHelper Class module and modify the Handle and JobDone subs as follows:

Handle:
B4X:
Dim sb As StringBuilder
            sb.Initialize
            sb.Append("secret=").Append(Main.settings.Get("RecaptchaPrivateKey"))
            sb.Append("&response=").Append(req.GetParameter("g-recaptcha-response"))
            j.PostString("https://www.google.com/recaptcha/api/siteverify", sb.ToString)
            StartMessageLoop

JobDone:
B4X:
Sub JobDone(j As HttpJob)
    If j.success Then
        Dim lines() As String = Regex.Split(CRLF, j.GetString)
        If lines.Length > 0 Then
            If lines(1).Contains("true") Then
                success = True
            Else
                success = False
                If lines.Length > 1 Then
                    errorMessage = "Some kind of error"
                End If
            End If
        End If
    Else
        success = False
        errorMessage = j.errorMessage
    End If
    j.Release
    StopMessageLoop
End Sub

That's it. It should now work with reCAPTCHA V2.
I didn't bother to change anything else which could take advantage of new features of B4X. I leave that to you.
 
Last edited:
Top