wwProcess::OnAuthenticateUser

This method/event is called when a user actually logs in with a username and password.

The method receives a username and password and optionally an error message string by reference. This method should validate the user based on the username and password and return .T. or .F. in response.

This method is internally called from Authenticate() and only fired when running in UserSecurity or Custom modes, which handle the display of the login form, writing the login information into the Session object and also retrieving the cached login information from the session object. Basically overriding this method allows you to handle only the Authentication/Login operation while leaving the rest of Web Connection's User Security mechanism untouched.

Implementing Custom Authentication/Login Validation

OnAuthenticateUser should be overridden in your own Process class. The following is the default implementation of OnAuthenticateUser which is easy to understand and override:

************************************************************************
*  OnAuthenticateUser
****************************************
***  Function: This method is called when a user needs to be authenticated
***            Use this to override the user authentication.
***      Pass: lcUsername     -   Username to validate
***            lcPassword     -   Password to validate
***            @lcErrorMsg    -   Error message to be set when auth fails
***    Return: .T. on success, .F. on Failure - should also set lcErrorMsg
************************************************************************
FUNCTION OnAuthenticateUser(lcUserName,lcPassword,lcErrorMsg)

*** THIS IS THE DEFAULT IMPLEMENTATION 
*** To override behavior override this method
IF EMPTY(lcUserName)
   lcUserName = ""
ENDIF 
IF EMPTY(lcPassword)
   lcPassword = ""
ENDIF

this.oUserSecurity = CREATEOBJECT(this.cAuthenticationUserSecurityClass)

*** Default implementation is not case sensitive
IF !this.oUserSecurity.Authenticate(LOWER(lcUserName),LOWER(lcPassword))
	*** Set lcErrorMsg to pass back via REF parm
	lcErrorMsg = this.oUserSecurity.cErrorMsg
	RETURN .F.
ENDIF	

*** Assign the user
this.oAuthenticatedUser = this.oUserSecurity.oUser
this.cAuthenticateUser = this.oAuthenticatedUser.UserName
this.cAuthenticateName = this.oAuthenticatedUser.FullName

Session.SetSessionVar(this.cAuthenticationUserSecurityKey,lcUsername)
RETURN .T.
ENDFUNC
*   OnAuthenticateUser

The method receives a username and password which your code should validate The method must return .T. or .F. to indicate whether the login operation succeeded or not. An optional @lcErrorMsg parameter is passed in which should be set to any error message that describes why a login failed.

Custom Implementation

A custom implementation might do a few things differently like use a custom business object for authentication and then store some commonly used values in Session Variables and local properties:

FUNCTION OnAuthenticateUser(lcUsername, lcPassword, lcErrorMsg)
LOCAL loUser

loUser =  CREATEOBJECT("ttUser")

*** This is not actually derived from user security but basic structure
*** is similar. Save/Load methods.
THIS.oUserSecurity = loUser

IF !loUser.AuthenticateAndLoad(lcUserName, lcPassword)
   this.cAuthenticatedUser = ""
   this.nAuthenticatedUserName = ""
   this.nAuthenticatedUserPk = -1
   lcErrorMsg = this.oUserSecurity.cErrorMsg 
   RETURN .F.
ENDIF

*** Assign our own variables we use in the application
this.cAuthenticatedUserName = loUser.oData.FullName
this.nAuthenticatedUserPk = loUser.oData.Pk

*** Assign Session vars so we can read them back in OnAuthenticated()
Session.SetSessionVar("AuthenticatedUsername",this.cAuthenticatedUserName)
Session.SetSessionVar("AuthenticatedUserPk", this.nAuthenticatedUserPk)

RETURN .T.
ENDFUNC

You typically use this method in combination with wwProcess:OnAuthenticated() which can be used after each request is validated to retrieve session values you stored when the user was originally authenticated:

FUNCTION OnAuthenticated()

*** Read custom Process Properties
this.cAuthenticatedUserName = Session.GetSessionVar("AuthenticatedUsername")
this.nAuthenticatedUserPk = VAL(Session.GetSessionVar("AuthenticatedUserPk"))

RETURN .T. 
o.OnAuthenticateUser(lcUsername,lcPassword,@lcErrorMsg)

Return Value

.T. on successful login, .F. on failed login (set lcErrorMsg with message)


Parameters

<>lcUsername<> The username to check

<>lcPassword<> The password to check

<>@lcErrorMsg<> An error message you should set when login fails.

Remarks

This method fires only when wwProcess::cAuthenticationMode is set to "UserSecurity". When implemented it overrides the use of the wwUserSecurity class and replaces it with your own authentication logic implemented in this method.

Example

The following demonstrates the full process of authentication

*********************************************************************
* Function ttprocess :: OnProcessInit
************************************
FUNCTION OnProcessInit
LOCAL lcScriptName, llForceLogin

THIS.InitSession("ttw")

lcScriptName = LOWER(JUSTFNAME(Request.GetPhysicalPath()))

llIgnoreLoginRequest = INLIST(lcScriptName,"default","login")

IF !THIS.Authenticate("any","",llIgnoreLoginRequest) 
   IF !llIgnoreLoginRequest
	  RETURN .F.
   ENDIF
ENDIF


Response.Encoding = "UTF8"
Request.lUtf8Encoding = .T.

RETURN .T.
ENDFUNC


************************************************************************
*  Login
****************************************
***  Function: Handles display of the login form if directly accessed
***            and routes postbacks to the Authenticate() method.
***    Assume:
***      Pass:
***    Return:
************************************************************************
FUNCTION Login()

pcErrorMessage = ""
IF Request.IsPostback()
   pcUsername = Request.Form("WebLogin_txtUsername")
   IF this.Authenticate("ANY",@pcErrorMessage)
      Response.Redirect("~/default.ttk")
   ENDIF
ENDIF

Response.ExpandScript(Config.cHtmlPagePath + "views\common\login.wcs")
ENDFUNC
*   Login

************************************************************************
*  Logout
****************************************
***  Function: Just a routing mechanism to allow logging out.
***    Assume:
***      Pass:
***    Return:
************************************************************************
FUNCTION Logout()
this.Authenticate("Logout")
Response.Redirect("default.ttk")
ENDFUNC
*   Logout

************************************************************************
*  OnShowAuthenticationForm
****************************************
***  Function: Show the authentication form. In this case it's simply
***            showing the application template.
***    Assume:
***      Pass:
***    Return:
************************************************************************
FUNCTION OnShowAuthenticationForm(lcUsername, lcErrorMsg)

pcUsername = lcUsername
pcPassword = ""
pcRedirectUrl = ""
pcErrorMessage = lcErrorMsg
IF EMPTY(pcUsername)
  pcUserName = ""
ENDIF

Response.ExpandScript(Config.cHtmlPagePath + "views\common\login.wcs")
ENDFUNC
*   OnShowAuthenticationForm


************************************************************************
*  OnAuthenticated
****************************************
***  Function: Called after a user has authenticated so we can read
***            values out of the session.
***    Assume:
***      Pass:
***    Return:
************************************************************************
FUNCTION OnAuthenticated()

*** Read custom Process Properties from Session which should be 
*** there since they were created when user originally signed in
this.cAuthenticatedUserName = Session.GetSessionVar("AuthenticatedUserName")
this.nAuthenticatedUserPk = VAL(Session.GetSessionVar("AuthenticatedUserPk"))

RETURN .T.   
ENDFUNC
*   OnAuthenticated

************************************************************************
*  OnAuthenticateUser
****************************************
***  Function: Handles validating username and password for the user
***    Assume:
***      Pass:
***    Return:
************************************************************************
FUNCTION OnAuthenticateUser(lcUsername, lcPassword, lcErrorMsg)
LOCAL loUser

loUser =  CREATEOBJECT("ttUser")

*** This is not actually derived from user security but basic structure
*** is similar. Save/Load methods.
THIS.oUserSecurity = loUser

IF !loUser.AuthenticateAndLoad(lcUserName, lcPassword)
   this.cAuthenticatedUser = ""
   this.cAuthenticatedUserName = ""
   this.nAuthenticatedUserPk = -1
   lcErrorMsg = this.oUserSecurity.cErrorMsg 
   RETURN .F.
ENDIF

*** Assign our own variables we use in the application
this.cAuthenticatedUserName = loUser.oData.UserName
this.nAuthenticatedUserPk = loUser.oData.Pk

*** Assign Session vars so we can read them back in OnAuthenticated()
Session.SetSessionVar("AuthenticatedUserName",this.cAuthenticatedUserName)
Session.SetSessionVar("AuthenticatedUserPk", this.nAuthenticatedUserPk)

RETURN .T.
ENDFUNC
*   OnAuthenticateUser

See also:

Class wwProcess | Custom Authentication with UserSecurity (Example) | UserSecurity Authentication

© West Wind Technologies, 1996-2018 • Updated: 09/09/15
Comment or report problem with topic