Skip to content

qwzhang01/seven-data-security

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

100 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Seven Data Security

License Maven Central Java Version Spring Boot MyBatis-Plus CI codecov

δΈ­ζ–‡ζ–‡ζ‘£

Seven Data Security is a comprehensive Spring Boot library for MyBatis that provides transparent data encryption, desensitization, and fine-grained data scope control for enterprise applications. It seamlessly integrates with MyBatis/MyBatis-Plus to automatically handle sensitive data protection without modifying business logic.

πŸ“‹ Table of Contents

✨ Features

πŸ” Automatic Data Encryption

  • Transparent encryption/decryption via annotations
  • Multiple encryption algorithms support (DES, AES, custom algorithms)
  • Zero business logic impact - encryption handled by interceptors
  • Type-safe Encrypt wrapper type for explicit encryption

πŸ” Query Parameter Encryption

  • Automatic parameter detection and encryption
  • Support for multiple parameter types: Map, Object, MyBatis-Plus QueryWrapper
  • Smart field matching with camelCase and snake_case conversion
  • Thread-safe parameter restoration after SQL execution

🎯 Data Scope Control

  • Row-level data filtering based on user permissions
  • Flexible strategy pattern for custom access rules
  • SQL rewriting with JOIN and WHERE conditions
  • Multi-tenant support for SaaS applications

πŸ“Š Development Tools

  • SQL statement printing with actual parameter values
  • Execution time tracking for performance monitoring
  • Environment-aware (disabled in production)

πŸ”„ SQL Processing

  • Single table query optimization with automatic table prefix
  • SQL rewriting for data scope injection
  • Smart column detection and processing

πŸ—οΈ Enterprise-Grade Design

  • Thread-safe operations with ThreadLocal context
  • Lazy initialization with caching for performance
  • Spring Boot auto-configuration
  • Extensible architecture via interfaces and abstract classes

πŸ›οΈ Architecture

seven-data-security
β”œβ”€β”€ config                  # Auto-configuration classes
β”‚   β”œβ”€β”€ JacksonConfig              # JSON serialization config
β”‚   β”œβ”€β”€ MaskAutoConfig             # Main auto-config
β”‚   └── MyBatisInterceptorAutoConfig  # MyBatis interceptors setup
β”œβ”€β”€ domain                  # Core domain models
β”‚   β”œβ”€β”€ AnnotatedField             # Field annotation metadata
β”‚   β”œβ”€β”€ Encrypt                    # Encryption wrapper type
β”‚   β”œβ”€β”€ EncryptInfo                # Parameter encryption context
β”‚   └── RestoreInfo                # Parameter restoration context
β”œβ”€β”€ encrypt                 # Encryption subsystem
β”‚   β”œβ”€β”€ annotation                 # @EncryptField annotation
β”‚   β”œβ”€β”€ container                  # Algorithm and metadata containers
β”‚   β”œβ”€β”€ context                    # Encryption context management
β”‚   β”œβ”€β”€ jackson                    # JSON serialization support
β”‚   β”œβ”€β”€ processor                  # Encryption/decryption processors
β”‚   β”‚   β”œβ”€β”€ DecryptProcessor       # Result decryption
β”‚   β”‚   β”œβ”€β”€ EncryptProcessor       # Parameter encryption
β”‚   β”‚   └── SingleSelectProcessor  # Single table SELECT optimization
β”‚   β”œβ”€β”€ shield                     # Encryption algorithm implementations
β”‚   └── type/handler               # MyBatis type handler
β”œβ”€β”€ interceptor             # MyBatis interceptors
β”‚   β”œβ”€β”€ DecryptInterceptor         # Result decryption
β”‚   β”œβ”€β”€ SqlPrintInterceptor        # SQL logging
β”‚   └── SqlRewriteInterceptor      # Parameter encryption & data scope
β”œβ”€β”€ kit                     # Utility classes
β”‚   β”œβ”€β”€ ClazzUtil                  # Reflection utilities
β”‚   β”œβ”€β”€ FieldMatchUtil             # Field matching logic
β”‚   β”œβ”€β”€ ParamUtil                  # Parameter processing
β”‚   β”œβ”€β”€ SpringContextUtil          # Spring context access
β”‚   β”œβ”€β”€ SqlPrint                   # SQL formatting
β”‚   └── StringUtil                 # String operations
β”œβ”€β”€ scope                   # Data scope subsystem
β”‚   β”œβ”€β”€ DataScopeHelper            # Scope context management
β”‚   β”œβ”€β”€ DataScopeStrategy          # Strategy interface
β”‚   β”œβ”€β”€ EmptyDataScopeStrategy     # Empty strategy implementation
β”‚   β”œβ”€β”€ container                  # Strategy container
β”‚   └── processor                  # SQL rewriting processor
└── exception               # Exception hierarchy
    β”œβ”€β”€ DataSecurityException      # Base exception
    └── JacksonException           # JSON-related exception

πŸš€ Quick Start

1. Add Dependency

Maven:

<dependency>
    <groupId>io.github.qwzhang01</groupId>
    <artifactId>seven-data-security</artifactId>
    <version>1.2.21</version>
</dependency>

Gradle:

implementation 'io.github.qwzhang01:seven-data-security:1.2.21'

2. Define Entity with Encryption

@Data
@TableName("user")
public class User {
    @TableId
    private Long id;
    
    private String username;
    
    // Automatically encrypted/decrypted
    @EncryptField
    private String phoneNumber;
    
    @EncryptField
    private String email;
    
    // Custom encryption algorithm
    @EncryptField(CustomAesAlgo.class)
    private String socialSecurityNumber;
}

3. Use in Service

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
    
    // Data is automatically encrypted before insert
    public void createUser(User user) {
        userMapper.insert(user);
    }
    
    // Data is automatically decrypted after query
    public User getUser(Long id) {
        return userMapper.selectById(id);
    }
    
    // Query parameters are automatically encrypted
    public List<User> findByPhone(String phone) {
        return userMapper.selectList(
            new QueryWrapper<User>().eq("phone_number", phone)
        );
    }
}

That's it! No additional code changes are required. The library automatically handles encryption and decryption.

πŸ”‘ Core Functionality

Field Encryption

Using @EncryptField Annotation

@Data
@TableName("customer")
public class Customer {
    @TableId
    private Long id;
    
    // Use default encryption algorithm
    @EncryptField
    private String phoneNumber;
    
    // Specify custom encryption algorithm
    @EncryptField(AesEncryptionAlgo.class)
    private String creditCard;
    
    private String name;
}

Using Encrypt Type Wrapper

@Data
@TableName("sensitive_data")
public class SensitiveData {
    @TableId
    private Long id;
    
    // Type-safe encryption wrapper
    private Encrypt secretData;
    
    // Getter returns plain text
    public String getSecretData() {
        return secretData.getValue();
    }
    
    // Setter accepts plain text
    public void setSecretData(String value) {
        this.secretData = new Encrypt(value);
    }
}

Custom Encryption Algorithm

public class AesEncryptionAlgo implements EncryptionAlgo {
    private static final String KEY = "YourSecretKey123"; // Use environment variable in production
    
    @Override
    public String encrypt(String value) {
        if (value == null) return null;
        // Implement AES encryption
        return AesUtils.encrypt(value, KEY);
    }
    
    @Override
    public String decrypt(String value) {
        if (value == null) return null;
        // Implement AES decryption
        return AesUtils.decrypt(value, KEY);
    }
}

Register Custom Algorithm

@Configuration
public class SecurityConfig {
    
    @Bean
    public AesEncryptionAlgo aesEncryptionAlgo() {
        return new AesEncryptionAlgo();
    }
}

Query Parameter Encryption

The library automatically encrypts query parameters that match encrypted fields:

// All these queries automatically encrypt the phone parameter
public class UserService {
    
    // Map parameters
    public List<User> findByPhone(String phone) {
        Map<String, Object> params = new HashMap<>();
        params.put("phoneNumber", phone);
        return userMapper.selectByMap(params);
    }
    
    // Object parameters
    public List<User> findUsers(UserQuery query) {
        return userMapper.selectList(query); // query.phoneNumber is auto-encrypted
    }
    
    // QueryWrapper parameters (MyBatis-Plus)
    public List<User> findWithWrapper(String phone) {
        return userMapper.selectList(
            new QueryWrapper<User>().eq("phone_number", phone) // auto-encrypted
        );
    }
    
    // XML Mapper parameters
    public List<User> findInXml(String phone) {
        return userMapper.findByPhone(phone); // auto-encrypted
    }
}

XML Mapper Example:

<select id="findByPhone" resultType="User">
    SELECT * FROM user WHERE phone_number = #{phoneNumber}
    <!-- phoneNumber is automatically encrypted before execution -->
</select>

Single Table Query Processing

The library automatically adds table prefix to columns in single-table SELECT queries, which helps prevent column name conflicts when used with data scope SQL rewriting:

// Original query
String sql = "SELECT id, name FROM user WHERE status = 1";

// After processing
String processedSql = "SELECT user.id, user.name FROM user WHERE user.status = 1";

Features:

  • βœ… Automatically detects single-table SELECT queries
  • βœ… Adds table prefix to SELECT columns, WHERE conditions, ORDER BY, GROUP BY, HAVING
  • βœ… Handles SELECT * β†’ SELECT table.* conversion
  • βœ… Respects table aliases
  • βœ… Skips queries with JOIN clauses (not single-table)

Use Cases:

  • Prevent ambiguous column names when data scope adds JOIN clauses
  • Improve SQL compatibility with complex query rewrites
  • Ensure consistent column references across different query types

Data Scope Control

Implement fine-grained data access control based on user permissions:

1. Define Data Scope Strategy

@Component
public class DepartmentDataScopeStrategy implements DataScopeStrategy<Long> {
    
    @Autowired
    private UserContext userContext;
    
    @Override
    public String join() {
        // Add JOIN clause if needed
        return "LEFT JOIN department d ON t.dept_id = d.id";
    }
    
    @Override
    public String where() {
        // Add WHERE clause for permission filtering
        List<Long> deptIds = userContext.getUserDepartmentIds();
        return "d.id IN (" + StringUtils.join(deptIds, ",") + ")";
    }
    
    @Override
    public void validDs(List<Long> validRights) {
        // Validate permissions for INSERT/UPDATE/DELETE
        Long currentDeptId = userContext.getCurrentDepartmentId();
        if (!validRights.contains(currentDeptId)) {
            throw new PermissionDeniedException("No permission for this department");
        }
    }
    
    @Override
    public void validDs(List<Long> validRights, List<Long> withoutRights) {
        // Whitelist support: if in whitelist, skip validation
        Long currentDeptId = userContext.getCurrentDepartmentId();
        if (withoutRights.contains(currentDeptId)) {
            return;
        }
        validDs(validRights);
    }
}

2. Apply Data Scope to Query

@Service
public class EmployeeService {
    
    @Autowired
    private EmployeeMapper employeeMapper;
    
    // Apply department-level data scope
    public List<Employee> getEmployees() {
        return DataScopeHelper
            .strategy(DepartmentDataScopeStrategy.class)
            .setSearchRight(getCurrentUserDeptIds())
            .execute(() -> employeeMapper.selectAll());
    }
    
    // Apply with validation for update
    public void updateEmployee(Employee employee) {
        DataScopeHelper
            .strategy(DepartmentDataScopeStrategy.class)
            .setValidRights(employee.getDeptId())
            .execute(() -> {
                employeeMapper.updateById(employee);
                return null;
            });
    }
    
    // Complex scenario with whitelist
    public void updateWithWhitelist(Employee employee) {
        List<Long> adminDepts = getAdminDepartments();
        DataScopeHelper
            .strategy(DepartmentDataScopeStrategy.class)
            .setValidRights(employee.getDeptId())
            .setWithoutRights(adminDepts) // Admin depts bypass validation
            .execute(() -> {
                employeeMapper.updateById(employee);
                return null;
            });
    }
}

Before Data Scope:

SELECT * FROM employee

After Data Scope Applied:

SELECT * FROM employee t 
LEFT JOIN department d ON t.dept_id = d.id
WHERE d.id IN (10, 20, 30)

SQL Printing

The library includes a powerful SQL printing feature for debugging:

# application-dev.yml (automatically enabled in non-prod environments)
spring:
  profiles:
    active: dev

Console Output:

=== SQL Execution ===
Method: com.example.mapper.UserMapper.selectById
SQL: SELECT * FROM user WHERE id = 1 AND phone_number = '_sensitive_start_EnCrYpTeD123='
Time: 15 ms
Returned: 1 rows

Features:

  • βœ… Shows actual parameter values (not placeholders)
  • βœ… Displays execution time
  • βœ… Shows affected/returned row counts
  • βœ… Automatically disabled in production (profile containing "prod")

βš™οΈ Configuration

Default Configuration

The library works out of the box with zero configuration. Default settings:

# These are implicit defaults, no need to configure
seven:
  data-security:
    encryption:
      algorithm: DES  # Default encryption algorithm
      key: "key12345678"  # Default key (change in production!)
    sql-print:
      enabled: true  # Enabled in non-production environments

Custom Configuration

Application Properties

spring:
  profiles:
    active: dev
  
# Custom encryption settings
seven:
  data-security:
    encryption:
      enabled: true
      algorithm: AES

Override Default Encryption Algorithm

@Configuration
public class EncryptionConfig {
    
    @Bean
    @Primary  // Make this the default algorithm
    public EncryptionAlgo defaultEncryptionAlgo() {
        return new MyCustomEncryptionAlgo();
    }
}

Disable SQL Printing

@Configuration
public class SqlPrintConfig {
    
    @Bean
    @ConditionalOnProperty(name = "sql.print.enabled", havingValue = "false")
    public ConfigurationCustomizer disableSqlPrint() {
        return configuration -> {
            // SQL printing will not be configured
        };
    }
}

πŸŽ“ Advanced Usage

Nested Object Encryption

@Data
public class Order {
    @TableId
    private Long id;
    
    // Nested object encryption
    private Customer customer;
    
    @Data
    public static class Customer {
        @EncryptField
        private String phone;
        
        @EncryptField
        private String email;
        
        private Address address;
        
        @Data
        public static class Address {
            @EncryptField
            private String street;
            
            private String city;
        }
    }
}

Collection Field Encryption

@Data
public class Company {
    @TableId
    private Long id;
    
    // List of encrypted fields
    private List<Employee> employees;
    
    @Data
    public static class Employee {
        @EncryptField
        private String socialSecurityNumber;
        
        private String name;
    }
}

Multi-Level Data Scope

// Combine multiple data scope strategies
public List<Document> getDocuments() {
    return DataScopeHelper
        .strategy(DepartmentDataScopeStrategy.class)
        .setSearchRight(userDeptIds)
        .execute(() -> 
            DataScopeHelper
                .strategy(ProjectDataScopeStrategy.class)
                .setSearchRight(userProjectIds)
                .execute(() -> documentMapper.selectAll())
        );
}

JSON Serialization

The library automatically handles Encrypt type serialization:

@RestController
public class UserController {
    
    @GetMapping("/user/{id}")
    public User getUser(@PathVariable Long id) {
        // Encrypt type fields are automatically serialized as plain strings
        return userService.getById(id);
    }
}

JSON Output:

{
  "id": 1,
  "username": "john",
  "phoneNumber": "13800138000",
  "email": "john@example.com"
}

🎨 Design Patterns

1. Strategy Pattern

  • EncryptionAlgo interface for pluggable encryption algorithms
  • DataScopeStrategy interface for customizable access control rules

2. Factory Pattern

  • AbstractEncryptAlgoContainer for algorithm instance creation and caching
  • Lazy initialization with Spring bean integration

3. Template Method Pattern

  • AbstractEncryptAlgoContainer provides template for algorithm resolution
  • Subclasses implement specific default algorithm logic

4. Singleton Pattern

  • DecryptProcessor and EncryptProcessor use Holder pattern for thread-safe singletons
  • SqlPrint utility uses inner Holder class

5. Interceptor Pattern

  • MyBatis Plugin mechanism for transparent encryption/decryption
  • Chain of responsibility for multiple interceptors

6. Observer Pattern

  • ObjectMapperEnhancer listens to ContextRefreshedEvent for Jackson configuration

7. Flyweight Pattern

  • Field metadata caching in ClazzUtil reduces reflection overhead
  • Algorithm instance caching in containers

⚑ Performance Considerations

Caching Mechanisms

  1. Reflection Cache: Field metadata cached in ConcurrentHashMap
  2. Algorithm Cache: Encryption algorithm instances cached
  3. Table Metadata Cache: MyBatis-Plus table info cached

Optimization Tips

// βœ… Good: Use @EncryptField for automatic encryption
@EncryptField
private String phoneNumber;

// ❌ Avoid: Manual encryption in business logic
private String phoneNumber;
public void setPhoneNumber(String phone) {
    this.phoneNumber = encryptionService.encrypt(phone); // Not recommended
}

// βœ… Good: Batch operations are efficiently handled
userMapper.insertBatch(users); // Encryption happens in single intercept call

// βœ… Good: QueryWrapper parameters are optimized
new QueryWrapper<User>().in("phone_number", phoneList); // Batch encryption

// ⚠️ Note: Disable encryption for non-sensitive fields
private String publicInfo; // No @EncryptField = No overhead

Performance Metrics

  • Encryption Overhead: ~1-2ms per field (DES algorithm)
  • Reflection Overhead: Negligible after first access (cached)
  • SQL Rewrite Overhead: < 1ms for data scope application

πŸ§ͺ Testing

Unit Test Example

@SpringBootTest
class UserServiceTest {
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private UserMapper userMapper;
    
    @Test
    void testEncryption() {
        // Create user with sensitive data
        User user = new User();
        user.setUsername("test");
        user.setPhoneNumber("13800138000");
        
        // Save user (encryption happens automatically)
        userService.createUser(user);
        
        // Query directly from database to verify encryption
        User dbUser = userMapper.selectById(user.getId());
        
        // Phone number should be decrypted automatically
        assertEquals("13800138000", dbUser.getPhoneNumber());
        
        // Verify data is encrypted in database
        String encryptedPhone = jdbcTemplate.queryForObject(
            "SELECT phone_number FROM user WHERE id = ?", 
            String.class, 
            user.getId()
        );
        assertTrue(encryptedPhone.startsWith("_sensitive_start_"));
    }
    
    @Test
    void testDataScope() {
        // Set up data scope context
        List<Employee> employees = DataScopeHelper
            .strategy(DepartmentDataScopeStrategy.class)
            .setSearchRight(Arrays.asList(10L, 20L))
            .execute(() -> employeeMapper.selectAll());
        
        // Verify only employees from departments 10 and 20 are returned
        assertTrue(employees.stream()
            .allMatch(e -> Arrays.asList(10L, 20L).contains(e.getDeptId())));
    }
}

🀝 Contributing

Contributions are welcome! Please follow these guidelines:

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/your-feature
  3. Commit your changes: git commit -am 'Add new feature'
  4. Push to the branch: git push origin feature/your-feature
  5. Submit a pull request

Development Setup

# Clone repository
git clone https://github.com/qwzhang01/seven-data-security.git
cd seven-data-security

# Build project
mvn clean install

# Run tests
mvn test

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ“ž Contact & Support

πŸ™ Acknowledgments

  • Thanks to the Spring Boot and MyBatis teams for their excellent frameworks
  • Thanks to all contributors who have helped improve this library

πŸ“š Additional Resources


Star ⭐ this repository if you find it helpful!

About

Seven Data Security is a comprehensive Spring Boot library for MyBatis that provides transparent data encryption, desensitization, and fine-grained data scope control for enterprise applications. It seamlessly integrates with MyBatis/MyBatis-Plus to automatically handle sensitive data protection without modifying business logic.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages