Building a Console-Based Student Management System with Java Authentication and Validation

Building an object-oreinted management application requires a clear separaiton between data persistence, business rules, and user interface logic. This implementation demonstrates a console-based authentication layer integrated with a core CRUD system, emphasizing validasion constraints and state management.

Architectural Components

The solution revolves around four primary entities:

  • ApplicationEntrance: Entry point handling session routing and menu dispatch.
  • AuthSubsystem: Manages account lifecycle including registration, credential verification, and recovery workflows.
  • DataValidator: Enforces strict formatting rules for identifiers, contact information, and credentials.
  • CoreModule: Executes the actual student data manipulation once access is granted.

Registration Workflow Constraints

Account creation triggers a multi-stage validation pipeline:

  1. Alias: Length between 3 and 15 characters. Must contain alphanumeric characters. Pure numeric strings are rejected. Uniqueness is enforced against the existing registry.
  2. Secret: Requires dual-entry confirmation to prevent typing errors.
  3. National ID: Exactly 18 digits. Cannot start with zero. Positions 0-16 must be numeric. Position 17 accepts digits or 'X'/'x'.
  4. Contact Number: Exactly 11 digits. Leading zero is invalid. Strictly numeric.

Authentication & Recovery Mechanics

Access is gated behind a secure checkpoint. After providing credentials, users must solve a generated CAPTCHA (4 random letters + 1 digit, shuffled positions). Failed authentications increment a retry counter, triggering a temporary blockout after three unsuccessful attempts. Password recovery cross-references the registered ID number and mobile number. Successful verification grants permission to overwrite the stored credential.

Implementation Details

The following code consolidates the architecture into a cohesive, executable unit. Structural improvements include isolated validation utilities, centralized input handling, and explicit state transitions.

import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;

public class ApplicationEntrance {
    private static final Scanner INPUT = new Scanner(System.in);
    private static final ArrayList<RegisteredUser> ACCOUNTS = new ArrayList<>();

    public static void main(String[] args) {
        while (true) {
            System.out.println("Welcome to the Academic Portal");
            System.out.println("Select action: 1. Login | 2. Register | 3. Recover Access");
            String selection = INPUT.next().trim();
            
            switch (selection) {
                case "1" -> performLogin();
                case "2" -> processRegistration();
                case "3" -> handleRecovery();
                case "4" -> { System.out.println("Session terminated."); System.exit(0); }
                default -> System.out.println("Invalid selection.");
            }
        }
    }

    private static void processRegistration() {
        String alias, secret, nationalId, contactNum;
        
        // Alias validation loop
        do {
            System.out.print("Enter username: ");
            alias = INPUT.next();
        } while (!isAliasValid(alias) || isAliasTaken(alias));
        System.out.println("Username available!");

        // Secret confirmation loop
        do {
            System.out.print("Create password: ");
            secret = INPUT.next();
            System.out.print("Confirm password: ");
        } while (!INPUT.next().equals(secret));
        System.out.println("Credentials matched.");

        // Identity validation loop
        do {
            System.out.print("Enter National ID: ");
            nationalId = INPUT.next();
        } while (!DataValidator.validateIdentity(nationalId));
        System.out.println("ID format verified.");

        // Contact validation loop
        do {
            System.out.print("Enter phone number: ");
            contactNum = INPUT.next();
        } while (!DataValidator.validatePhone(contactNum));
        System.out.println("Phone format verified.");

        RegisteredUser newUser = new RegisteredUser(alias, secret, nationalId, contactNum);
        ACCOUNTS.add(newUser);
        System.out.println("Registration complete.");
        printRegistry();
    }

    private static void performLogin() {
        int attempts = 0;
        while (attempts < 3) {
            System.out.print("Enter username: ");
            String submittedUser = INPUT.next();
            if (!isAliasTaken(submittedUser)) {
                System.out.println("Account not found. Please register first.");
                return;
            }
            System.out.print("Enter password: ");
            String submittedPass = INPUT.next();

            while (true) {
                String captchaCode = generateCaptcha();
                System.out.println("CAPTCHA: " + captchaCode);
                System.out.print("Input CAPTCHA: ");
                String userInputCode = INPUT.next();
                if (userInputCode.equalsIgnoreCase(captchaCode)) break;
                System.out.println("Incorrect CAPTCHA. Retry.");
            }

            RegisteredUser target = findAccount(submittedUser);
            if (target != null && target.getSecret().equals(submittedPass)) {
                System.out.println("Authentication successful. Entering portal...");
                CoreModule.startAcademicSession();
                return;
            }
            
            System.out.println("Invalid credentials. Remaining attempts: " + (2 - attempts));
            attempts++;
        }
        System.out.println("Account locked due to excessive failures. Contact support.");
    }

    private static void handleRecovery() {
        System.out.print("Enter username: ");
        String requestedUser = INPUT.next();
        RegisteredUser target = findAccount(requestedUser);
        if (target == null) {
            System.out.println("Account does not exist.");
            return;
        }

        System.out.print("Enter National ID: ");
        String providedId = INPUT.next();
        System.out.print("Enter Phone Number: ");
        String providedPhone = INPUT.next();

        if (!providedId.equalsIgnoreCase(target.getId()) || !providedPhone.equals(target.getPhone())) {
            System.out.println("Verification failed. Information mismatch.");
            return;
        }

        System.out.print("New password: ");
        String newPass = INPUT.next();
        System.out.print("Confirm new password: ");
        if (INPUT.next().equals(newPass)) {
            target.setSecret(newPass);
            System.out.println("Password updated successfully.");
        } else {
            System.out.println("Mismatch detected. Update cancelled.");
        }
    }

    private static String generateCaptcha() {
        char[] letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
        Random rng = new Random();
        StringBuilder builder = new StringBuilder();
        
        for (int i = 0; i < 4; i++) {
            builder.append(letters[rng.nextInt(letters.length)]);
        }
        builder.append(rng.nextInt(10));
        
        char[] chars = builder.toString().toCharArray();
        int swapIdx = rng.nextInt(chars.length);
        char temp = chars[chars.length - 1];
        chars[chars.length - 1] = chars[swapIdx];
        chars[swapIdx] = temp;
        
        return new String(chars);
    }

    private static boolean isAliasValid(String alias) {
        int len = alias.length();
        if (len < 3 || len > 15) return false;
        for (char c : alias.toCharArray()) {
            if (!Character.isLetterOrDigit(c)) return false;
        }
        long digitCount = alias.chars().filter(Character::isDigit).count();
        return digitCount < alias.length(); // Rejects pure numbers
    }

    private static boolean isAliasTaken(String alias) {
        return findAccount(alias) != null;
    }

    private static RegisteredUser findAccount(String alias) {
        for (RegisteredUser acc : ACCOUNTS) {
            if (acc.getAlias().equals(alias)) return acc;
        }
        return null;
    }

    private static void printRegistry() {
        for (RegisteredUser acc : ACCOUNTS) {
            System.out.printf("%s, %s, %s, %s%n", acc.getAlias(), acc.getSecret(), acc.getId(), acc.getPhone());
        }
    }
}

// ==========================================
// SUPPORTING CLASSES
// ==========================================
class DataValidator {
    public static boolean validateIdentity(String id) {
        if (id.length() != 18 || id.startsWith("0")) return false;
        for (int i = 0; i < 17; i++) {
            if (!Character.isDigit(id.charAt(i))) return false;
        }
        char last = id.charAt(17);
        return Character.isDigit(last) || last == 'X' || last == 'x';
    }

    public static boolean validatePhone(String num) {
        if (num.length() != 11 || num.startsWith("0")) return false;
        for (char c : num.toCharArray()) {
            if (!Character.isDigit(c)) return false;
        }
        return true;
    }
}

class RegisteredUser {
    private String alias;
    private String secret;
    private String id;
    private String phone;

    public RegisteredUser(String alias, String secret, String id, String phone) {
        this.alias = alias;
        this.secret = secret;
        this.id = id;
        this.phone = phone;
    }
    public String getAlias() { return alias; }
    public String getSecret() { return secret; }
    public void setSecret(String secret) { this.secret = secret; }
    public String getId() { return id; }
    public String getPhone() { return phone; }
}

class CoreModule {
    private static final ArrayList<EnrolledStudent> STUDENTS = new ArrayList<>();
    private static final Scanner SCAN = new Scanner(System.in);

    public static void startAcademicSession() {
        label: while (true) {
            System.out.println("\n--- ACADEMIC DASHBOARD ---");
            System.out.println("1. Add | 2. Remove | 3. Update | 4. List | 5. Exit");
            String cmd = SCAN.next().trim();
            switch (cmd) {
                case "1" -> addStudent();
                case "2" -> removeStudent();
                case "3" -> updateStudent();
                case "4" -> listStudents();
                case "5" -> break label;
                default -> System.out.println("Unknown command.");
            }
        }
    }

    private static void addStudent() {
        String id;
        do {
            System.out.print("Enter Student ID: ");
            id = SCAN.next();
        } while (findStudentIndex(id) != -1);
        System.out.print("Name: "); String name = SCAN.next();
        System.out.print("Age: "); int age = SCAN.nextInt();
        System.out.print("Location: "); String loc = SCAN.next();
        STUDENTS.add(new EnrolledStudent(id, name, age, loc));
        System.out.println("Added successfully.");
    }

    private static void removeStudent() {
        System.out.print("ID to delete: ");
        String id = SCAN.next();
        int idx = findStudentIndex(id);
        if (idx >= 0) {
            STUDENTS.remove(idx);
            System.out.println("Removed.");
        } else System.out.println("Not found.");
    }

    private static void updateStudent() {
        System.out.print("ID to modify: ");
        String id = SCAN.next();
        int idx = findStudentIndex(id);
        if (idx == -1) { System.out.println("Record missing."); return; }
        EnrolledStudent s = STUDENTS.get(idx);
        System.out.print("New Name: "); s.setName(SCAN.next());
        System.out.print("New Age: "); s.setAge(SCAN.nextInt());
        System.out.print("New Location: "); s.setLocation(SCAN.next());
        System.out.println("Updated.");
    }

    private static void listStudents() {
        if (STUDENTS.isEmpty()) { System.out.println("No records."); return; }
        System.out.printf("%-10s %-15s %-5s %s%n", "ID", "Name", "Age", "Location");
        for (EnrolledStudent s : STUDENTS) System.out.printf("%-10s %-15s %-5d %s%n", s.getId(), s.getName(), s.getAge(), s.getLocation());
    }

    private static int findStudentIndex(String id) {
        for (int i = 0; i < STUDENTS.size(); i++) {
            if (STUDENTS.get(i).getId().equals(id)) return i;
        }
        return -1;
    }
}

class EnrolledStudent {
    private String id;
    private String name;
    private int age;
    private String location;
    public EnrolledStudent(String id, String name, int age, String location) {
        this.id = id; this.name = name; this.age = age; this.location = location;
    }
    public String getId() { return id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public String getLocation() { return location; }
    public void setLocation(String location) { this.location = location; }
}

Expected Execution Flow

Welcome to the Academic Portal
Select action: 1. Login | 2. Register | 3. Recover Access
2
Enter username: zhangsan
Username available!
Enter Create password: zs123456
Confirm password: zs123456
Credentials matched.
Enter National ID: 342423202407150001
ID format verified.
Enter Phone Number: 12345678912
Phone format verified.
Registration complete.
zhangsan, zs123456, 342423202407150001, 12345678912

Welcome to the Academic Portal
Select action: 1. Login | 2. Register | 3. Recover Access
1
Enter username: zhangsan
Enter password: zs123456
CAPTCHA: ct0bS
Input CAPTCHA: ct0bs
Authentication successful. Entering portal...

--- ACADEMIC DASHBOARD ---
1. Add | 2. Remove | 3. Update | 4. List | 5. Exit
5

Welcome to the Academic Portal
Select action: 1. Login | 2. Register | 3. Recover Access
3
Enter username: zhangsan
Enter National ID: 342423202407150001
Enter Phone Number: 12345678912
New password: zs1234567
Confirm new password: zs1234567
Password updated successfully.

Tags: java Object-Oriented Programming console applications Authentication Data Validation

Posted on Wed, 19 Aug 2026 16:04:40 +0000 by jrdiller