Registration - Aligheri/jwt-owasp-based-starter GitHub Wiki

Overview

This documentation covers the user registration functionality in your Spring Boot application, which provides a flexible and extensible registration system through abstract base classes and interfaces.

Architecture

The registration system follows a template method pattern with the following key components:

Core Interfaces and Classes

RegisterRequest Interface

The base interface that defines the contract for registration requests:

public interface RegisterRequest {
    String getEmail();
    String getPassword();
    String getUsername();
}

DefaultRegistrationRequest Class

A default implementation of the RegisterRequest interface:

@Getter
@Setter
@Data
@NoArgsConstructor
public class DefaultRegistrationRequest implements RegisterRequest {
    private String username;
    private String password;
    private String email;
}

Abstract Registration Method

The base registration method that must be implemented by subclasses:

V registerUser(U registrationRequest);

@Override
public V registerUser(U registrationRequest) {
    throw new UnsupportedOperationException("registerUser must be overridden in subclass");
}

Implementation Guide

Step 1: Implement the Registration Service

Override the registerUser method in your authentication service:

@Override
public DefaultRegisterResponse registerUser(DefaultRegistrationRequest request) {
    // Validate username uniqueness
    if (userRepository.existsByUsername(request.getUsername())) {
        return new DefaultRegisterResponse("Error: Username is already taken!");
    }

    // Validate email uniqueness
    if (userRepository.existsByEmail(request.getEmail())) {
        return new DefaultRegisterResponse("Error: Email is already in use!");
    }

    // Create new user entity
    User user = new User();
    user.setUsername(request.getUsername());
    user.setEmail(request.getEmail());
    user.setPassword(passwordEncoder.encode(request.getPassword()));
    
    // Set user status
    UserStatus userStatus = UserStatus.builder()
            .user(user)
            .enabled(true)
            .accountLocked(false)
            .build();

    user.setUserStatus(userStatus);
    userRepository.save(user);

    // Handle account activation
    String code = activationService.generateActivationCode(user.getEmail());
    activationService.sendActivationEmail(user.getEmail(), code);

    return new DefaultRegisterResponse("User registered successfully!");
}

Step 2: Create the REST Controller

Implement the registration endpoint:

@PostMapping("/register")
public ResponseEntity<DefaultRegisterResponse> registerUser(
    @Valid @RequestBody DefaultRegistrationRequest defaultRegistrationRequest) {
    
    logger.info("Attempting to register user: {}", defaultRegistrationRequest.getUsername());
    
    try {
        DefaultRegisterResponse defaultRegisterResponse = 
            authenticationService.registerUser(defaultRegistrationRequest);
        
        logger.info("User registered successfully: {}", defaultRegistrationRequest.getUsername());
        return ResponseEntity.ok(defaultRegisterResponse);
        
    } catch (RegisterException e) {
        return ResponseEntity.badRequest().body(new DefaultRegisterResponse(e.getMessage()));
    }
}

Key Features

1. Data Validation

  • Username Uniqueness: Checks if the username is already taken
  • Email Uniqueness: Validates that the email address is not already registered
  • Input Validation: Uses @Valid annotation for request body validation

2. Password Security

  • Passwords are encoded using a PasswordEncoder before storage
  • Never store plain text passwords in the database

3. User Status Management

  • Creates a UserStatus entity with default values:
    • enabled: true
    • accountLocked: false

4. Account Activation

The registration process includes email activation functionality through the ActivationService:

5. Error Handling

  • Handles duplicate username/email scenarios gracefully
  • Uses custom RegisterException for error management
  • Returns appropriate HTTP status codes

6. Logging

  • Comprehensive logging for registration attempts and outcomes
  • Helps with debugging and monitoring

Response Format

The registration endpoint returns a DefaultRegisterResponse object with:

  • Success message for successful registrations
  • Error message for failed registrations

Security Considerations

  1. Password Encoding: All passwords are encoded before database storage
  2. Input Validation: Request data is validated using Bean Validation annotations
  3. Duplicate Prevention: Prevents duplicate usernames and emails
  4. Account Activation: Email verification adds an additional security layer

Extension Points

The architecture allows for easy customization:

  1. Custom Registration Requests: Implement the RegisterRequest interface for additional fields
  2. Custom Validation Logic: Override the registerUser method to add business-specific validation
  3. Custom Response Types: Define custom response classes for different registration scenarios

Dependencies

Ensure you have the following dependencies in your project:

  • Spring Boot Starter Web
  • Spring Boot Starter Data JPA
  • Spring Boot Starter Validation
  • Spring Boot Starter Security (for password encoding)
  • Your custom authentication starter package

Usage Example

POST /register
Content-Type: application/json

{
    "username": "john_doe",
    "email": "[email protected]",
    "password": "securePassword123"
}

Success Response:

{
    "message": "User registered successfully!"
}

Error Response:

{
    "message": "Error: Username is already taken!"
}