Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Building a Community Epidemic Prevention and Control Platform with Spring Boot and Vue.js

Tech May 10 4

Technical Architecture

The backend service is powered by the Spring Boot framework. This framework leverages an embedded Tomcat container, removing the need for manual WAR file deployment. Its auto-configuration mechanism adapts application settings based on detected classpath dependencies, significantly reducing manual XML configuration. The ecosystem supports various production-ready tools, including Spring Security and data integration modules, to ensure robust application delivery.

The frontend is constructed using Vue.js. The library employs a Virtual DOM strategy to optimize rendering performance by minimizing actual DOM manipulation. Its reactive data binding model ensures the view layer stays synchronized with the underlying data state, allowing developers to prioritize business logic over UI manipulation.

Persistence is handled via MyBatis-Plus. This enhancement tool extends standard MyBatis capabilities by providing powerful CRUD wrappers. It integrates features such as pagination plugins and dynamic SQL builders, facilitating rapid and secure access to databases like MySQL.

System Testing and Validation

The testing strategy primarily employs black-box techniques to verify that system behavior meets requirements without inspecting internal code structures.

Functional Verification

Authentication Module: Test cases verify that access is granted when valid credentials are submitted. The system also confirms that logic correctly rejects invalid passwords, incorrect CAPTCHA inputs, and empty username fields. Scenarios also check for the presence of specific role validation logic within the database.

User Management: This module underwent testing against Create, Read, Update, and Delete (CRUD) operations. The validation process ensures the system enforces non-null constraints when mandatory fields are missing. Additionally, the system checks for uniqueness constraints (rejecting duplicate usernames) and verifies that deletion operations permanently remove records from both the view and data store.

Implementation Code Examples

Authentication Controller

The following controller handles authentication requests, validating credentials and generating a session token.

@RestController
@RequestMapping("/api/v1/auth")
public class AuthController {

    @Autowired
    private UserService userService;

    @Autowired
    private TokenManager tokenManager;

    @PostMapping("/login")
    public ResponseEntity<Map<String, Object>> authenticate(@RequestBody CredentialsDto credentials, HttpServletRequest request) {
        UserProfile user = userService.retrieveByUsername(credentials.getUsername());
        
        if (user == null || !userService.validatePassword(user, credentials.getPassword())) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                    .body(Map.of("status", "error", "message", "Invalid username or password"));
        }

        String authToken = tokenManager.issueToken(user.getId(), user.getUsername(), user.getRole());
        return ResponseEntity.ok(Map.of("status", "success", "token", authToken));
    }
}

Token Generation Service

This service generates secure random tokens and manages them with an expiration time.

@Service
public class TokenManager {

    @Autowired
    private SessionRepository sessionRepository;

    public String issueToken(Long userId, String username, String role) {
        String rawToken = generateSecureString();
        LocalDateTime expiration = LocalDateTime.now().plusHours(1);
        
        SessionEntity existingSession = sessionRepository.findByUserId(userId);
        
        if (existingSession != null) {
            existingSession.setToken(rawToken);
            existingSession.setExpiryDate(expiration);
            sessionRepository.update(existingSession);
        } else {
            SessionEntity newSession = new SessionEntity(userId, username, role, rawToken, expiration);
            sessionRepository.save(newSession);
        }
        
        return rawToken;
    }
    
    private String generateSecureString() {
        // Implementation for generating a random 32-char string
        return UUID.randomUUID().toString().replace("-", "").substring(0, 32);
    }
}

Security Interceptor

This interceptor ensures that requests to protected endpoints contain a valid authentication token.

@Component
public class SecurityInterceptor implements HandlerInterceptor {

    public static final String AUTH_HEADER = "X-Auth-Token";

    @Autowired
    private TokenManager tokenManager;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // Handle CORS preflight requests
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpStatus.OK.value());
            return false;
        }

        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        // Bypass authentication for methods annotated with PublicEndpoint
        HandlerMethod method = (HandlerMethod) handler;
        if (method.getMethodAnnotation(PublicEndpoint.class) != null) {
            return true;
        }

        String clientToken = request.getHeader(AUTH_HEADER);
        if (StringUtils.isNotBlank(clientToken) && tokenManager.validateToken(clientToken)) {
            return true;
        }

        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setContentType("application/");
        try {
            response.getWriter().write("{\"error\":\"Unauthorized\"}");
        } catch (IOException e) {
            // Log error
        }
        return false;
    }
}

Database Schema Reference

The following SQL script defines the table structure for storing user sessions and authentication tokens.

-- Drop existing table if it exists
DROP TABLE IF EXISTS `user_sessions`;

-- Create the session table
CREATE TABLE `user_sessions` (
  `session_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 'Primary Key',
  `user_id` BIGINT(20) NOT NULL COMMENT 'Associated User ID',
  `username` VARCHAR(100) NOT NULL COMMENT 'Username',
  `role_name` VARCHAR(50) DEFAULT NULL COMMENT 'User Role',
  `auth_token` VARCHAR(200) NOT NULL COMMENT 'Authentication Token',
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation Time',
  `expires_at` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Token Expiration',
  PRIMARY KEY (`session_id`) USING BTREE,
  INDEX `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='User Session Storage';

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.