The Authenticate method uses UserSecurity
authorization to handle:
- User Authentication by username and password
- Validating an
Authorization
Bearer Token for a valid login - Logging by removing/invalidating a token and the active session
wwRestProcess::Authenticate()
uses thewwSession
class and requires a call toInitTokenSession()
(implicitly made if you didn't call it yourself), but it doesn't use Cookies like the basewwProcess
class does. The REST authentication replaces Cookie authentication with Bearer Token Authentication.
To do this this method can be called in three ways:
Authenticate(lcUsername, lcPassword)
User Authentication Mode
With two parameters it authenticates a user based on a passed in username and password and updates the new session and various wwProcess authentication properties. As with the no-parameter version all the user related properties are populated if the authentication succeeds. If it fails a401 Unauthorized
response is returned.Authenticate()
Token Validation Mode
With no parameters this method is in Validation Mode validates a user and assigns the various wwProcess authentication properties if the user is authenticated. In essence the User token is mapped to a UserSecurity record (by default - you can override this behavior) if the check succeeds, and if it fails results in a401 Unauthorized
response.Authenticate("LOGOUT")
Logout Mode
This simple operation is meant to remove an existing token. You need to be signed in and provide a Bearer token in theAuthorization
header and that active session and token will then be removed.
This mechanism is based on Bearer Token authentication which assumes that a token is passed in the Authorization
header of the request coming from the client:
Authorization: Bearer x312d2dasdas2
The token is stored using the wwSession object along with user security information.
Implementation
There are three distinct operations that need to be performed:
- Check if a user is already signed in (in
OnProcessInit()
) - Sign in a user
- Sign out a user
Check if a User is Signed in
To check if a user is signed in you need to check on every request that has to be authenticated. The following assumes all requests need to be authenticated except those on the ignore list:
FUNCTION OnProcessInit
...
*** IMPORTANT: InitTokenSession is required to pick up the Bearer token
*** and load or create a new session
THIS.InitTokenSession()
*** Check for pages that should bypass auth - signin always (not signout though!)
lcScriptName = LOWER(JUSTFNAME(Request.GetPhysicalPath()))
llIgnoreLoginRequest = INLIST(lcScriptName,"testage","signin")
IF !llIgnoreLoginRequest
*** Check for Authentication here based on the token (note no parameters)
IF !this.Authenticate()
THIS.ErrorResponse("Access Denied. Please sign in first.","401 Unauthorized")
RETURN .F. && Response is handled
ENDIF
ENDIF
RETURN .T.
ENDFUNC
The call to InitTokenSession()
creates a session based on the passed Bearer token
in the Authorization
header.
The call to Authorize()
maps the token from the session to a UserSecurity
object and the various Auth properties on the wwRestProcess
class.
Signin
In order for users to sign in and create the initial token you need to pass credentials into a specific request - here called Signin
. You use the credentials to validate the user. By default a username and password is validated against the user security class configured.
FUNCTION SignIn(loCredentials)
LOCAL loToken, llError, lcErrorMsg, lcToken, ltExpires
lcErrorMsg = ""
lcToken = ""
TRY
*** Sign in: If successful sets oUserSecurity, lIsAuthenticated, cAuthenticatedUser etc.
IF this.Authenticate(loCredentials.Username, loCredentials.Password)
lcToken = Session.cSessionId
ltExpires = Session.oData.FirstOn + Session.nSessionTimeout
*** Set any custom values you might need
Session.SetSessionVar("tenant","TENANT_ID")
Session.Save() && Explicit save: Session on REST Services don't save by default
ELSE
lcErrorMsg = "Invalid Credentials..."
llError = .T.
ENDIF
CATCH TO loException
lcErrorMsg = loException.Message
llError = .T.
ENDTRY
IF llError
RETURN THIS.ErrorResponse(lcErrorMsg,"401 Not Authorized")
ENDIF
*** Response
loToken = CREATEOBJECT("EMPTY")
ADDPROPERTY(loToken,"token", lcToken)
ADDPROPERTY(loToken,"expires", ltExpires)
** Add other client cachable user data here as properties if you need
RETURN loToken
ENDFUNC
* Signin
Once the user has logged in the user is reloaded on every request if a valid token is provided.
Signout
If you need to explicitly sign out a user you can do so using an explicit method like this:
FUNCTION Signout()
THIS.Authenticate("LOGOUT")
JsonService.IsRawResponse = .T.
Response.Write( [{ message: "Successfully logged out." }])
ENDFUNC
* Signout
In order to sign out you have to be signed in with a token. The token determines which session record is removed once you sign out.
Overriding functionality
As in the HTML wwProcess
class you can override parts of the Authentication process. For example if you want to use some other authentication mechanism than User Security you can do that by overriding OnAuthenticateUser
for example, without having to rewrite the entire Authentication logic.
o.wwRestProcess.Authenticate(lcUsername, lcPassword)
Parameters
lcUsername
lcPassword
See also:
Class wwRestProcess© West Wind Technologies, 1996-2024 • Updated: 11/13/23
Comment or report problem with topic