Alovoa - 开源隐私优先的约会平台

项目标题与描述

Alovoa是一个旨在成为首个广泛使用的免费开源约会网络平台。与其他平台不同,Alovoa具有以下核心价值:

  • 无广告
  • 不出售用户数据
  • 无付费功能(无"付费超级喜欢"、"付费滑动"、"付费查看资料"或"付费开始聊天")
  • 安全的服务器
  • 完全开源
  • 提供高级筛选功能避免看到不想见的人
  • 最隐私的数据采用安全加密

功能特性

核心功能

  • 用户注册与认证系统
  • 个人资料管理(包括图片、音频、个人描述等)
  • 基于地理位置和兴趣的匹配系统
  • 实时聊天功能
  • 验证码系统防止滥用
  • 管理员后台管理
  • 多语言支持
  • 响应式设计支持移动端

安全特性

  • 端到端文本加密
  • 验证码保护关键操作
  • 敏感数据加密存储
  • GDPR合规设计
  • 账户删除功能

技术亮点

  • 基于Spring Boot的后端架构
  • JPA/Hibernate数据持久层
  • Spring Security安全框架
  • RESTful API设计
  • 支持Docker部署
  • 支持MariaDB数据库

安装指南

系统要求

  • Java 17+
  • Maven
  • MariaDB数据库
  • 邮件服务器

本地开发环境安装

  1. 安装OpenJDK 17
  2. 安装Maven
  3. 设置MariaDB数据库
  4. 配置邮件服务器
  5. 在application.properties中配置数据库、邮件服务器和加密密钥
  6. 执行mvn install

Docker部署

docker-compose build
docker-compose up -d
docker-compose logs -f

数据库设置

# 开发数据库
mysql -uroot -e "CREATE DATABASE alovoa DEFAULT CHARACTER SET utf8"
mysql -uroot -e "CREATE USER 'alovoa'@'localhost' IDENTIFIED BY 'alovoa'"
mysql -uroot -e "GRANT ALL PRIVILEGES ON alovoa.* TO 'alovoa'@'localhost'"

# 测试数据库
mysql -uroot -e "CREATE DATABASE alovoa_test DEFAULT CHARACTER SET utf8"
mysql -uroot -e "CREATE USER 'alovoa_test'@'localhost' IDENTIFIED BY 'alovoa_test'"
mysql -uroot -e "GRANT ALL PRIVILEGES ON alovoa_test.* TO 'alovoa_test'@'localhost'"

使用说明

API使用示例

获取验证码

@RestController
@RequestMapping("/captcha")
public class CaptchaController {
    @Autowired
    private CaptchaService captchaService;

    @GetMapping("/generate")
    public Captcha generate() throws NoSuchAlgorithmException, IOException {
        return captchaService.generate();
    }
}

用户注册

@RestController
@RequestMapping("/")
public class RegisterController {
    @Autowired
    private RegisterService registerService;

    @PostMapping(value = "/register", consumes = "application/json")
    public void register(@RequestBody RegisterDto dto) throws Exception {
        registerService.register(dto);
    }
}

搜索用户

@Controller
@RequestMapping("/search")
public class SearchController {
    @Autowired
    private SearchService searchService;

    @GetMapping("/users/default")
    public String getUsersDefault(Model model) throws Exception {
        model.addAttribute("dto", searchService.searchComplete());
        return "fragments :: search-users";
    }
}

核心代码

应用主入口

@SpringBootApplication
@EnableJpaRepositories("com.nonononoki.alovoa.repo")
@EntityScan("com.nonononoki.alovoa.entity")
@EnableCaching
@EnableScheduling
public class AlovoaApplication {
    public static void main(String[] args) {
        Security.addProvider(new BouncyCastleProvider());
        SpringApplication.run(AlovoaApplication.class, args);
    }
}

用户实体类

@Entity
public class User implements UserDetails {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(nullable = false, unique = true)
    @Convert(converter = TextEncryptorConverter.class)
    @JsonIgnore
    private String email;
    
    @JsonIgnore
    private String password;
    
    @Convert(converter = TextEncryptorConverter.class)
    private String firstName;
    
    private String description;
    private int units;
    private boolean showZodiac;
    private int preferedMinAge;
    private int preferedMaxAge;
    
    // 其他字段和方法...
}

文本加密转换器

@Component
public class TextEncryptorConverter implements AttributeConverter<String, String> {
    @Value("${app.text.key}")
    private String key;
    
    @Value("${app.text.salt}")
    private String salt;

    private static final String TRANSFORMATION = "AES/CBC/PKCS5PADDING";

    @Override
    public String convertToDatabaseColumn(String attribute) {
        try {
            return encode(attribute);
        } catch (Exception e) {
            throw new DatabaseRuntimeException(e);
        }
    }

    private String encode(String attribute) throws Exception {
        if(attribute == null) return null;
        byte[] ba = getEnCipher().doFinal(attribute.getBytes(StandardCharsets.UTF_8));
        return Base64.getUrlEncoder().encodeToString(ba);
    }
    // 其他方法...
}

验证码服务

@Service
public class CaptchaService {
    @Autowired
    private CaptchaRepository captchaRepo;

    public Captcha generate() throws NoSuchAlgorithmException, IOException {
        OxCaptcha ox = generateCaptchaImage();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(ox.getImage(), "webp", baos);
        byte[] ba = baos.toByteArray();
        String encoded = Base64.getEncoder().encodeToString(ba);
        
        Captcha captcha = new Captcha();
        captcha.setImage(encoded);
        captcha.setText(ox.getText());
        return captchaRepo.saveAndFlush(captcha);
    }
    // 其他方法...
}

更多精彩内容 请关注我的个人公众号 公众号(办公AI智能小助手)
公众号二维码

posted @ 2025-06-29 20:01  qife  阅读(35)  评论(0)    收藏  举报