B4J Tutorial [Server] Login System & Filters Tutorial

Discussion in 'B4J Tutorials' started by Erel, Mar 19, 2014.

  1. Erel

    Erel Administrator Staff Member Licensed User

    upload_2014-3-19_16-8-41.png
    Try it online: http://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:

    [​IMG]

    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:
    Code:
    Public Sub Filter(req As ServletRequest, resp As ServletResponseAs 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):
    Code:
    srvr.AddFilter("/login_example/members/*""MembersFilter"False)
    The filter code:
    Code:
    Public Sub Filter(req As ServletRequest, resp As ServletResponseAs 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
    Code:
    nohup ../jre1.7.0_51/bin/java -jar ServerExample.jar > nohup.out &
    - The project depends on the following B4A libraries: ByteConverter and Encryption
     

    Attached Files:

    Last edited: Jan 14, 2016
    MarkusR, cambopad, BarryW and 4 others like this.
  2. Claudio Oliveira

    Claudio Oliveira Active Member Licensed 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
     
  3. Erel

    Erel Administrator Staff Member Licensed User

    The Filter feature is not available in the beta version. Hopefully the full version will be released tomorrow.
     
    Claudio Oliveira likes this.
  4. Claudio Oliveira

    Claudio Oliveira Active Member Licensed User

    Thanks Erel
     
  5. AscySoft

    AscySoft Active Member Licensed 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?
     
  6. Erel

    Erel Administrator Staff Member Licensed User

    Have you tried the online example? This is exactly the purpose of the filter.
     
  7. AscySoft

    AscySoft Active Member Licensed User

  8. Erel

    Erel Administrator Staff Member Licensed User

    Reports is not protected by this filter. It is a different example.

    The filter is applied to:
    Code:
    srvr.AddFilter("/login_example/members/*""MembersFilter"False)
     
  9. AscySoft

    AscySoft Active Member Licensed User

    So how to protect ANY other examples, links from a server? <<Is it by setting a global variable and filter it in every class/handler in my server?>>
     
  10. Erel

    Erel Administrator Staff Member Licensed User

    No.

    You should let the filter process all requests:
    Code:
    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.
     
  11. AscySoft

    AscySoft Active Member Licensed User

    Let's say I would like the idea of filtering all the requests. How should I modify this. Is this correct:
    Code:
    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?
     
  12. Erel

    Erel Administrator Staff Member Licensed User

    Almost. You need to return true even if more than 30 minutes passed in that case.
     
  13. AscySoft

    AscySoft Active Member Licensed User

    No, because I like the idea of "timeout" in 30 minutes if no activity. So, I nust try with
    Code:
    req.FullRequestURI.Contains("login page")
    Thanks
     
  14. Erel

    Erel Administrator Staff Member Licensed User

    Your code is wrong. You should fix it.
     
  15. AscySoft

    AscySoft Active Member Licensed User

    Could you be so kind and past the fixed code?
     
  16. Erel

    Erel Administrator Staff Member Licensed User

    Read my answer in post #13 again.
     
  17. LucaMs

    LucaMs Expert Licensed 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:
    Code:
    srvr.StaticFilesFolder = File.Combine(File.DirApp, "www")
    here not.

    Thanks
     
    Last edited: Jul 29, 2014
  18. Erel

    Erel Administrator Staff Member Licensed User

    In order for the communication between the browser and the server to be safe you need to use SSL (https).

    www is the default static folder.
     
  19. LucaMs

    LucaMs Expert Licensed User


    Thanks, Erel
     
  20. tuicemen

    tuicemen Member Licensed User

    while trying to load this example I get a pop up the following libraries are missing:
    byteconverter
    encryption
    Where do I find these?
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice