comments
This commit is contained in:
@@ -1,6 +1,13 @@
|
||||
package org.example.petshopdesktop.auth;
|
||||
|
||||
/*
|
||||
Petshop Desktop
|
||||
Purpose: Application role definitions used by session state and role based access control.
|
||||
*/
|
||||
public enum Role {
|
||||
// Administrative access, includes system management screens.
|
||||
ADMIN,
|
||||
|
||||
// Staff access, limited to day to day operational screens.
|
||||
STAFF
|
||||
}
|
||||
|
||||
@@ -1,14 +1,24 @@
|
||||
package org.example.petshopdesktop.auth;
|
||||
|
||||
/*
|
||||
Petshop Desktop
|
||||
Purpose: In memory session state for the authenticated user.
|
||||
Notes: Session is process local and cleared on logout or application restart.
|
||||
*/
|
||||
public class UserSession {
|
||||
|
||||
// Singleton instance used to share session state across controllers.
|
||||
private static UserSession instance;
|
||||
|
||||
// Current authenticated username, null when logged out.
|
||||
private String username;
|
||||
|
||||
// Current authenticated role, null when logged out.
|
||||
private Role role;
|
||||
|
||||
private UserSession() {}
|
||||
|
||||
// Lazily initialised singleton accessor.
|
||||
public static UserSession getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new UserSession();
|
||||
@@ -16,11 +26,13 @@ public class UserSession {
|
||||
return instance;
|
||||
}
|
||||
|
||||
// Stores identity and role for the active session.
|
||||
public void login(String username, Role role) {
|
||||
this.username = username;
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
// Clears session state and returns the application to an unauthenticated state.
|
||||
public void logout() {
|
||||
this.username = null;
|
||||
this.role = null;
|
||||
@@ -34,10 +46,13 @@ public class UserSession {
|
||||
return role;
|
||||
}
|
||||
|
||||
// Convenience check for administrative privileges.
|
||||
// Role.ADMIN.equals(role) remains safe when role is null.
|
||||
public boolean isAdmin() {
|
||||
return Role.ADMIN.equals(role);
|
||||
}
|
||||
|
||||
// Session is considered active only when both username and role are set.
|
||||
public boolean isLoggedIn() {
|
||||
return username != null && role != null;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,10 @@ import org.example.petshopdesktop.models.User;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/*
|
||||
Petshop Desktop
|
||||
Purpose: Authentication controller responsible for validating credentials and initialising the user session.
|
||||
*/
|
||||
public class LoginController {
|
||||
|
||||
@FXML
|
||||
@@ -27,15 +31,18 @@ public class LoginController {
|
||||
|
||||
@FXML
|
||||
void btnLoginClicked(ActionEvent event) {
|
||||
// Input normalisation keeps authentication behaviour consistent.
|
||||
String username = txtUsername.getText().trim();
|
||||
String password = txtPassword.getText();
|
||||
|
||||
// Basic validation to avoid unnecessary database calls.
|
||||
if (username.isEmpty() || password.isEmpty()) {
|
||||
lblError.setText("Please enter username and password.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Credential verification returns a fully populated User on success.
|
||||
User user = UserDB.authenticate(username, password);
|
||||
if (user == null) {
|
||||
lblError.setText("Invalid username or password.");
|
||||
@@ -43,6 +50,7 @@ public class LoginController {
|
||||
return;
|
||||
}
|
||||
|
||||
// Session state is stored in memory for use by controllers and UI RBAC.
|
||||
UserSession.getInstance().login(user.getUsername(), user.getRole());
|
||||
openMainLayout();
|
||||
|
||||
@@ -53,6 +61,7 @@ public class LoginController {
|
||||
|
||||
private void openMainLayout() {
|
||||
try {
|
||||
// View transition into the post login application shell.
|
||||
FXMLLoader loader = new FXMLLoader(
|
||||
getClass().getResource("/org/example/petshopdesktop/main-layout-view.fxml"));
|
||||
Scene scene = new Scene(loader.load());
|
||||
|
||||
@@ -11,6 +11,10 @@ import javafx.scene.layout.StackPane;
|
||||
import javafx.stage.Stage;
|
||||
import org.example.petshopdesktop.auth.UserSession;
|
||||
|
||||
/*
|
||||
Petshop Desktop
|
||||
Purpose: Main application shell controller, includes navigation and UI level role based access control.
|
||||
*/
|
||||
public class MainLayoutController {
|
||||
|
||||
@FXML
|
||||
@@ -108,6 +112,7 @@ public class MainLayoutController {
|
||||
|
||||
@FXML
|
||||
void btnLogoutClicked(ActionEvent event) {
|
||||
// Logout clears session state before returning to the login view.
|
||||
UserSession.getInstance().logout();
|
||||
try {
|
||||
FXMLLoader loader = new FXMLLoader(
|
||||
@@ -124,16 +129,22 @@ public class MainLayoutController {
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
// RBAC state is applied once during initial layout load.
|
||||
applyRBAC();
|
||||
|
||||
// Default landing view after successful authentication.
|
||||
loadView("pet-view.fxml");
|
||||
}
|
||||
|
||||
private void applyRBAC() {
|
||||
UserSession session = UserSession.getInstance();
|
||||
|
||||
// Session identity is displayed in the header for clarity and auditing.
|
||||
lblUsername.setText(session.getUsername());
|
||||
lblRole.setText(session.getRole().toString());
|
||||
|
||||
// UI level RBAC hides admin only navigation entries for non admin users.
|
||||
// setManaged(false) removes the node from layout calculations to avoid empty spacing.
|
||||
boolean isAdmin = session.isAdmin();
|
||||
btnInventory.setVisible(isAdmin);
|
||||
btnInventory.setManaged(isAdmin);
|
||||
@@ -141,6 +152,8 @@ public class MainLayoutController {
|
||||
btnSuppliers.setManaged(isAdmin);
|
||||
btnProductSuppliers.setVisible(isAdmin);
|
||||
btnProductSuppliers.setManaged(isAdmin);
|
||||
|
||||
// Privileged operations should still be enforced within the relevant controllers and database methods.
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,6 +5,10 @@ import org.example.petshopdesktop.models.User;
|
||||
|
||||
import java.sql.*;
|
||||
|
||||
/*
|
||||
Petshop Desktop
|
||||
Purpose: User authentication and role lookup against the users table.
|
||||
*/
|
||||
public class UserDB {
|
||||
|
||||
/**
|
||||
@@ -29,7 +33,11 @@ public class UserDB {
|
||||
if (rs.next()) {
|
||||
int userId = rs.getInt("user_id");
|
||||
String uname = rs.getString("username");
|
||||
|
||||
// Role values are stored in the database as strings and normalised to match the enum.
|
||||
// Table constraints limit role values, Role.valueOf is expected to be safe under normal operation.
|
||||
Role role = Role.valueOf(rs.getString("role").toUpperCase());
|
||||
|
||||
return new User(userId, uname, role);
|
||||
}
|
||||
}
|
||||
@@ -51,6 +59,7 @@ public class UserDB {
|
||||
)
|
||||
""";
|
||||
|
||||
// Default accounts support initial development and testing, credentials should be rotated or removed for deployment.
|
||||
String seedAdmin = """
|
||||
INSERT IGNORE INTO users (username, password_hash, role)
|
||||
VALUES ('admin', SHA2('admin123', 256), 'ADMIN')
|
||||
|
||||
Reference in New Issue
Block a user