API: Accessing User Data
Relevant source files
The following files were used as context for generating this wiki page:- API/src/main/java/xyz/xreatlabs/nexauth/api/database/ReadWriteDatabaseProvider.java
- API/src/main/java/xyz/xreatlabs/nexauth/api/database/User.java
- API/src/main/java/xyz/xreatlabs/nexauth/api/database/ReadDatabaseProvider.java
- API/src/main/java/xyz/xreatlabs/nexauth/api/database/WriteDatabaseProvider.java
- Plugin/src/main/java/xyz/xreatlabs/nexauth/common/database/AuthenticUser.java
- Plugin/src/main/java/xyz/xreatlabs/nexauth/common/database/provider/NexAuthSQLDatabaseProvider.java
- Plugin/src/main/java/xyz/xreatlabs/nexauth/common/AuthenticNexAuth.java
The NexAuth API provides a structured and extensible system for interacting with user authentication data. It abstracts the underlying database implementation through a set of clear interfaces, allowing for consistent data handling across different storage backends like MySQL, PostgreSQL, and SQLite. This system is centered around the User data model and a series of DatabaseProvider interfaces that segregate read and write operations.
The core of the data access layer is the ReadWriteDatabaseProvider, which is the main provider used by the plugin. It combines data retrieval and modification functionalities. The API also allows for the registration of custom database providers and connectors, making it flexible for various server setups and data migration needs.
Core Components
The data access layer is built upon several key interfaces and their implementations. These components define the structure of user data and the contracts for database interactions.
Data Access Interfaces
The API defines separate interfaces for reading and writing data, which are then combined into a single read-write interface. This design promotes a clear separation of concerns.
This diagram shows the relationship between the primary data access interfaces.
Sources: API/src/main/java/xyz/xreatlabs/nexauth/api/database/ReadDatabaseProvider.java, API/src/main/java/xyz/xreatlabs/nexauth/api/database/WriteDatabaseProvider.java, API/src/main/java/xyz/xreatlabs/nexauth/api/database/ReadWriteDatabaseProvider.java, Plugin/src/main/java/xyz/xreatlabs/nexauth/common/database/AuthenticDatabaseProvider.java, Plugin/src/main/java/xyz/xreatlabs/nexauth/common/database/provider/NexAuthSQLDatabaseProvider.java
ReadDatabaseProvider: Defines methods for retrievingUserobjects from the database based on various criteria like name, UUID, or IP address.WriteDatabaseProvider: Defines methods for creating, updating, and deletingUserrecords in the database.ReadWriteDatabaseProvider: A marker interface that combines bothReadDatabaseProviderandWriteDatabaseProvider, representing a fully functional data source. The main plugin instance uses an implementation of this interface.AuthenticDatabaseProvider: An abstract base class that implementsReadWriteDatabaseProviderand holds a reference to aDatabaseConnectorand the main plugin instance.
The User Data Model
The User interface is the central data structure representing a player's authentication information. The primary implementation is AuthenticUser.
This diagram illustrates the relationship between the User interface and its concrete implementation, AuthenticUser.
The table below details the fields available in the AuthenticUser implementation.
| Field | Type | Description |
|---|---|---|
uuid | UUID | The unique identifier for the user, which can be generated based on the new-uuid-creator config. |
premiumUUID | UUID | The user's official Mojang UUID if they are a premium player. Null otherwise. |
hashedPassword | HashedPassword | The user's hashed password, salt, and algorithm. Null if the user is not registered. |
lastNickname | String | The last known in-game name of the user. |
joinDate | Timestamp | The timestamp of when the user first joined. |
lastSeen | Timestamp | The timestamp of when the user was last seen on the server. |
secret | String | The secret key for TOTP (2FA). Null if 2FA is not enabled for the user. |
ip | String | The last known IP address of the user. |
lastAuthentication | Timestamp | The timestamp of the user's last successful authentication. |
lastServer | String | The name of the last server the user was connected to. Used if remember-last-server is enabled. |
email | String | The user's email address, used for password recovery. |
Sources: Plugin/src/main/java/xyz/xreatlabs/nexauth/common/database/AuthenticUser.java:15-29, Plugin/src/main/java/xyz/xreatlabs/nexauth/common/config/ConfigurationKeys.java:150, Plugin/src/main/java/xyz/xreatlabs/nexauth/common/config/ConfigurationKeys.java:302
Data Retrieval (ReadDatabaseProvider)
The ReadDatabaseProvider interface provides several methods to fetch user data. All read operations are designed to be executed off the main server thread to prevent performance issues. The NexAuthSQLDatabaseProvider implementation warns if an I/O operation is performed on the main thread.
Sources: Plugin/src/main/java/xyz/xreatlabs/nexauth/common/database/provider/NexAuthSQLDatabaseProvider.java:33, Plugin/src/main/java/xyz/xreatlabs/nexauth/common/AuthenticNexAuth.java:1010-1014
| Method | Parameters | Returns | Description |
|---|---|---|---|
getByIP | String ip | Collection<User> | Retrieves all users associated with a specific IP address. |
getByName | String name | User | Retrieves a single user by their last known nickname (case-insensitive). |
getAllUsers | (none) | Collection<User> | Retrieves all users from the database. Used primarily for data migration. |
getByUUID | UUID uuid | User | Retrieves a single user by their unique ID. |
getByPremiumUUID | UUID uuid | User | Retrieves a single user by their premium (Mojang) UUID. |
Sources: API/src/main/java/xyz/xreatlabs/nexauth/api/database/ReadDatabaseProvider.java:15-46, Plugin/src/main/java/xyz/xreatlabs/nexauth/common/database/provider/NexAuthSQLDatabaseProvider.java:51-57
The following sequence diagram shows the flow for retrieving a user by name.
Data Modification (WriteDatabaseProvider)
The WriteDatabaseProvider interface handles all create, update, and delete (CRUD) operations for user data.
| Method | Parameters | Returns | Description |
|---|---|---|---|
insertUser | User user | void | Inserts a single new user into the database. |
insertUsers | Collection<User> users | void | Inserts a collection of users, typically in a batch operation for efficiency (e.g., during migration). |
updateUser | User user | void | Updates an existing user's record in the database, identified by their UUID. |
deleteUser | User user | void | Deletes a user's record from the database, identified by their UUID. |
Sources: API/src/main/java/xyz/xreatlabs/nexauth/api/database/WriteDatabaseProvider.java:15-39
Database Schema (librepremium_data)
The NexAuthSQLDatabaseProvider defines and validates a specific table schema named librepremium_data.
This ER diagram shows the structure of the main user data table.
The validateSchema method ensures that the table exists and contains all necessary columns, adding any that are missing. This allows for seamless updates to the database structure between plugin versions.
// From: Plugin/src/main/java/xyz/xreatlabs/nexauth/common/database/provider/NexAuthSQLDatabaseProvider.java
@Override
public void validateSchema() {
connector.runQuery(connection -> {
connection.prepareStatement(
"CREATE TABLE IF NOT EXISTS librepremium_data(" +
"uuid VARCHAR(255) NOT NULL PRIMARY KEY," +
"premium_uuid VARCHAR(255) UNIQUE," +
"hashed_password VARCHAR(255)," +
"salt VARCHAR(255)," +
"algo VARCHAR(255)," +
"last_nickname VARCHAR(255) NOT NULL UNIQUE," +
"joined TIMESTAMP NULL DEFAULT NULL," +
"last_seen TIMESTAMP NULL DEFAULT NULL," +
"last_server VARCHAR(255)" +
")"
).executeUpdate();
var columns = getColumnNames(connection);
// ... ALTER TABLE statements to add columns like 'secret', 'ip', etc. if they don't exist
if (!columns.contains("secret"))
connection.prepareStatement("ALTER TABLE librepremium_data ADD COLUMN secret VARCHAR(255) NULL DEFAULT NULL").executeUpdate();
// ...
});
}
Summary
The NexAuth data access API is a robust, interface-driven system that cleanly separates data models from storage logic. By defining distinct ReadDatabaseProvider and WriteDatabaseProvider interfaces, it establishes a clear contract for data interaction. The User object serves as a comprehensive data carrier for all player-related authentication details. The SQL implementation demonstrates how these interfaces are realized, including schema validation to ensure database integrity and facilitate smooth upgrades. This architecture provides stability for the core plugin while offering extensibility for developers.