Implementing a Smart Elderly Care Platform with SpringBoot, Vue, and UniApp: Architecture and Authentication Design

Technology Stack Overview

The smart elderly care platform adopts a separated frontend and backend architecture. The backend leverages Spring Boot as the core framework, which simplifies application configuration through its auto-configuration mechanism. It includes embedded servers like Tomcat, eliminating the need for external server deployment. Spring Boot integrates seamlessly with Spring Data, Spring Security, and Spring Cloud, providing extensibility for enterprise-level applications.

The frontend utilizes Vue.js, which employs a reactive data binding system combined with a virtual DOM. When data changes occur, the view updates automatically, allowing developers to focus on business logic rather than manual DOM manipulation. The component-based architecture promotes code reusability and maintainability.

For data persistence, MyBatis-Plus serves as an enhancement to the traditional MyBatis framework. It provides a code generator for creating entity classes, mapper interfaces, and XML mapping files. Additional features include pagination queries, dynamic query construction, and optimistic locking support.

Authentication and Token Management Implementation

The platform implements a token-based authentication system. When users log in, the system validates credentials and generates a unique token for subsequent requests.

Login Controller

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

    @Autowired
    private SysUserService sysUserService;
    
    @Autowired
    private AccessTokenService accessTokenService;

    @SkipAuthCheck
    @PostMapping("/signin")
    public ResponseEntity<ApiResponse> authenticateUser(
            @RequestParam String account,
            @RequestParam String secret,
            @RequestParam(required = false) String verifyCode) {
        
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.eq("account", account);
        SysUser currentUser = sysUserService.getOne(wrapper);
        
        if (currentUser == null || !currentUser.getSecret().equals(secret)) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                    .body(ApiResponse.fail("Invalid credentials"));
        }
        
        String accessToken = accessTokenService.createAccessToken(
                currentUser.getId(), 
                account, 
                "sys_user", 
                currentUser.getRoleType()
        );
        
        return ResponseEntity.ok(ApiResponse.success().data("accessToken", accessToken));
    }
}

Token Generation Service

@Service
public class AccessTokenService {

    @Autowired
    private AccessTokenDao accessTokenDao;

    private static final int TOKEN_VALIDITY_HOURS = 24;

    public String createAccessToken(Long uid, String account, String entityName, String roleType) {
        QueryWrapper<AccessToken> query = new QueryWrapper<>();
        query.eq("uid", uid).eq("role_type", roleType);
        AccessToken existingToken = accessTokenDao.selectOne(query);
        
        String newTokenValue = UUID.randomUUID().toString().replace("-", "");
        Calendar expiryTime = Calendar.getInstance();
        expiryTime.add(Calendar.HOUR, TOKEN_VALIDITY_HOURS);
        
        if (existingToken != null) {
            existingToken.setTokenValue(newTokenValue);
            existingToken.setExpireTime(expiryTime.getTime());
            accessTokenDao.updateById(existingToken);
        } else {
            AccessToken freshToken = new AccessToken();
            freshToken.setUid(uid);
            freshToken.setAccount(account);
            freshToken.setEntityName(entityName);
            freshToken.setRoleType(roleType);
            freshToken.setTokenValue(newTokenValue);
            freshToken.setExpireTime(expiryTime.getTime());
            accessTokenDao.insert(freshToken);
        }
        
        return newTokenValue;
    }

    public AccessToken fetchTokenEntity(String tokenValue) {
        QueryWrapper<AccessToken> query = new QueryWrapper<>();
        query.eq("token_value", tokenValue);
        AccessToken token = accessTokenDao.selectOne(query);
        if (token != null && token.getExpireTime().after(new Date())) {
            return token;
        }
        return null;
    }
}

Authorization Interceptor

@Component
public class AuthInterceptor implements HandlerInterceptor {

    private static final String HEADER_TOKEN_KEY = "X-Access-Token";

    @Autowired
    private AccessTokenService accessTokenService;

    @Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {
        
        res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        res.setHeader("Access-Control-Max-Age", "3600");
        res.setHeader("Access-Control-Allow-Credentials", "true");
        res.setHeader("Access-Control-Allow-Headers", 
                "Content-Type, X-Access-Token, Origin, Accept, Authorization");
        res.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));

        if (req.getMethod().equalsIgnoreCase("OPTIONS")) {
            res.setStatus(HttpServletResponse.SC_OK);
            return false;
        }

        SkipAuthCheck skipAnnotation = null;
        if (handler instanceof HandlerMethod) {
            skipAnnotation = ((HandlerMethod) handler).getMethodAnnotation(SkipAuthCheck.class);
        } else {
            return true;
        }

        if (skipAnnotation != null) {
            return true;
        }

        String tokenFromHeader = req.getHeader(HEADER_TOKEN_KEY);
        AccessToken tokenEntity = null;
        
        if (StringUtils.hasText(tokenFromHeader)) {
            tokenEntity = accessTokenService.fetchTokenEntity(tokenFromHeader);
        }

        if (tokenEntity != null) {
            req.getSession().setAttribute("currentUid", tokenEntity.getUid());
            req.getSession().setAttribute("currentRole", tokenEntity.getRoleType());
            req.getSession().setAttribute("currentAccount", tokenEntity.getAccount());
            return true;
        }

        res.setContentType("application/json;charset=UTF-8");
        res.getWriter().write(JSONObject.toJSONString(ApiResponse.fail(401, "Authentication required")));
        return false;
    }
}

Database Schema Design

The token management table stores session information for authenticated users.

-- Access Token Table Structure
DROP TABLE IF EXISTS `access_token`;
CREATE TABLE `access_token` (
  `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 'Primary Key',
  `uid` BIGINT(20) NOT NULL COMMENT 'User ID',
  `account` VARCHAR(100) NOT NULL COMMENT 'Account Name',
  `entity_name` VARCHAR(100) DEFAULT NULL COMMENT 'Entity Table',
  `role_type` VARCHAR(100) DEFAULT NULL COMMENT 'User Role',
  `token_value` VARCHAR(200) NOT NULL COMMENT 'Token String',
  `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation Time',
  `expire_time` TIMESTAMP NOT NULL DEFAULT '1970-01-01 00:00:01' COMMENT 'Expiration Time',
  PRIMARY KEY (`id`),
  INDEX `idx_uid_role` (`uid`, `role_type`),
  INDEX `idx_token` (`token_value`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Access Token Storage';

-- Sample Data
INSERT INTO `access_token` VALUES 
(1, 1, 'admin', 'sys_user', 'administrator', 'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6', NOW(), DATE_ADD(NOW(), INTERVAL 24 HOUR)),
(2, 15, 'nurse_wang', 'staff', 'caregiver', 'q1w2e3r4t5y6u7i8o9p0a1s2d3f4g5h6', NOW(), DATE_ADD(NOW(), INTERVAL 24 HOUR)),
(3, 28, 'elder_zhang', 'elderly', 'senior', 'z9x8c7v6b5n4m3l2k1j0h9g8f7d6s5a4', NOW(), DATE_ADD(NOW(), INTERVAL 24 HOUR));

System Testing Methodology

The testing process employs black-box testing techniques to validate system functionality from an end-user perspective. Test cases are designed to cover normal operations, boundary conditions, and error handling scenarios.

Login Functionality Test Cases

Test InputExpected OutcomeActual ResultStatus
Account: admin, Password: correct_pwd, Captcha: validLogin successfulToken generated, redirect to dashboardPass
Account: admin, Password: wrong_pwd, Captcha: validAuthentication failedError: Invalid credentialsPass
Account: admin, Password: correct_pwd, Captcha: invalidCaptcha verification failedError: Captcha mismatchPass
Account: empty, Password: any, Captcha: anyValidation errorError: Account requiredPass
Account: admin, Password: empty, Captcha: anyValidation errorError: Password requiredPass

User Management Test Cases

OperationTest DataExpected ResultStatus
Create UserValid user data with all required fieldsUser created, appears in listPass
Create UserMissing required field (username)Error: Username cannot be emptyPass
Create UserDuplicate usernameError: Username already existsPass
Update UserModified user detailsChanges saved successfullyPass
Delete UserSelect user for deletionConfirmation prompt, user removed after confirmPass

Testing validates that the authentication flow handles various input scenarios correctly, including invalid credentials, missing fields, and expired tokens. The interceptor properly enforces access control for protected endpoints while allowing public routes to function without authentication.

Tags: SpringBoot Vue.js UniApp Smart Healthcare Token Authentication

Posted on Thu, 07 May 2026 03:05:48 +0000 by smokey20