User Management
Overview
TMS Sphinx provides a comprehensive set of tools for managing user authentication and authorization in Delphi applications. Central to this functionality is the IUserManager interface, which offers a variety of methods for handling user-related operations such as creating, updating, and deleting users, as well as managing advanced security features like two-factor authentication.
The ISphinxContext Interface
ISphinxContext is an interface that manages the lifecycle of user-related objects. It ensures that user objects are properly maintained and destroyed when no longer needed. Obtaining a user manager through a context is recommended because it guarantees the correct management of user object lifetimes.
Retrieving the Sphinx Context
To retrieve the ISphinxContext, you use the TSphinxServer.CreateContext method of the TSphinxServer component. This method provides a ready-to-use context for managing users.
Example:
procedure TForm1.SetupSphinxContext;
var
Context: ISphinxContext;
begin
// Retrieve the Sphinx context from the SphinxServer component
Context := SphinxServer1.CreateContext;
end;
The IUserManager Interface
The IUserManager interface provides a variety of methods for managing users in the database. Here is a detailed list of the main tasks you can accomplish using IUserManager.
Creating a User
You can create a user with or without a password using the IUserManager.CreateUser method.
Example:
var
User: TUser;
begin
User := Context.UserManager.CreateUserInstance;
User.UserName := 'newuser';
User.Email := 'newuser@example.com';
Context.UserManager.CreateUser(User, 'password123');
end;
Updating a User
To update user details, use the IUserManager.UpdateUser method.
Example:
User.Email := 'newemail@example.com';
Context.UserManager.UpdateUser(User);
Deleting a User
To delete a user from the database, use the IUserManager.DeleteUser method.
Example:
Context.UserManager.DeleteUser(User);
Finding Users
You can find users by their ID, username, email, or phone number using methods such as IUserManager.FindById, IUserManager.FindByName, IUserManager.FindByEmail, and IUserManager.FindByPhoneNumber.
Example:
User := Context.UserManager.FindByName('newuser');
if User <> nil then
ShowMessage('User found: ' + User.Email);
Checking Password
To check if a provided password is correct for a user, use the IUserManager.CheckPassword method.
Example:
if Context.UserManager.CheckPassword(User, 'password123') then
ShowMessage('Password is correct');
Email and Phone Number Confirmation
You can generate confirmation tokens and confirm email and phone numbers using the respective methods.
Example for Email Confirmation:
var
Token: string;
begin
Token := Context.UserManager.GenerateEmailConfirmationToken(User);
// Send token to user via email and later confirm
Context.UserManager.ConfirmEmail(User, Token);
end;
Example for Phone Number Confirmation:
var
Token: string;
begin
Token := Context.UserManager.GeneratePhoneNumberConfirmationToken(User);
// Send token to user via SMS and later confirm
Context.UserManager.ConfirmPhoneNumber(User, Token);
end;
Password Management
To manage user passwords, use methods for generating reset tokens, changing passwords, and adding passwords.
Example for Resetting Password:
var
ResetToken: string;
NewPasswordToken: string;
begin
ResetToken := Context.UserManager.GeneratePasswordResetToken(User);
// Send reset token to user and later exchange it for a change password token
NewPasswordToken := Context.UserManager.BeginResetPassword(User, ResetToken);
// Change the password using the new password token
Context.UserManager.ChangePassword(User, NewPasswordToken, 'newpassword123');
end;
Two-Factor Authentication
You can force users to enable two-factor authentication (2fa) and use it to login. You can do this by setting TLoginOptions.RequireTwoFactor property to true
:
SphinxConfig1.LoginOptions.RequireTwoFactor := True;
When 2fa is required for the user and the user tries to login with a simple password, the login application will also display a QR Code for the user to enable 2fa via authentication app (e.g., Google Authenticator or similar), and ask for the code. If the user provides the correct code, 2fa will be enabled and then authenticator code will be needed whenever the user tries to login in future.
If you want to require 2fa only for a few selected users, you can use the IUserManager.SetTwoFactorRequired method for that specific user:
procedure RequireTwoFactorAuthentication(Context: ISphinxContext; const UserName: string);
var
User: TUser;
UserManager: IUserManager;
begin
// Retrieve the user
User := Context.UserManager.FindByName(UserName);
if User = nil then
raise Exception.Create('User not found');
UserManager := Context.UserManager;
// Require two-factor authentication next time user tries to login
UserManager.SetTwoFactorRequired(User, True);
end;
You can also fully enable and manage two-factor authentication yourself, in case you want to display the QR Code in your own app. You can use methods to retrieve, reset, and verify the authenticator key.
Example for Enabling Two-Factor Authentication manually:
procedure EnableTwoFactorAuthentication(Context: ISphinxContext; const UserName: string);
var
User: TUser;
UserManager: IUserManager;
AuthenticatorKey: string;
begin
// Retrieve the user
User := Context.UserManager.FindByName(UserName);
if User = nil then
raise Exception.Create('User not found');
UserManager := Context.UserManager;
// Enable two-factor authentication
UserManager.SetTwoFactorEnabled(User, True);
// Ensure the user has an authenticator key
if Context.UserManager.GetAuthenticatorKey(User) = '' then
Context.UserManager.ResetAuthenticatorKey(User);
// Retrieve the authenticator key
AuthenticatorKey := Context.UserManager.GetAuthenticatorKey(User);
// Display the QR code URI
Log('Two-factor QR code URI: ' + TOtpUri.Build(AuthenticatorKey, 'YourApp', UserName));
end;
Lockout Management
To manage user lockouts, you can use methods like IUserManager.IsLockedOut, IUserManager.AccessFailed, and IUserManager.ResetAccessFailedCount.
Example:
if Context.UserManager.IsLockedOut(User) then
ShowMessage('User is locked out');
Context.UserManager.AccessFailed(User); // Increment failed access count
Context.UserManager.ResetAccessFailedCount(User); // Reset the failed access count
Token Management
You can generate and validate tokens for various purposes, such as email confirmation and password reset.
Example:
var
Token: string;
begin
Token := Context.UserManager.GenerateUserToken(User, 'ProviderName', 'Purpose');
if Context.UserManager.VerifyUserToken(User, 'ProviderName', 'Purpose', Token) then
ShowMessage('Token is valid');
end;
Authentication Tokens
You can save, retrieve, and remove authentication tokens using the respective methods.
Example:
// Save a token
Context.UserManager.SetAuthenticationToken(User, 'LoginProvider', 'TokenName', 'TokenValue');
// Retrieve a token
var
TokenValue: string;
begin
TokenValue := Context.UserManager.GetAuthenticationToken(User, 'LoginProvider', 'TokenName');
ShowMessage('Token: ' + TokenValue);
// Remove a token
Context.UserManager.RemoveAuthenticationToken(User, 'LoginProvider', 'TokenName');