当前位置: 首页 > news >正文

Spring Boot 实现验证码生成与校验:从零开始构建安全登录系统

📝 前言

在当今的互联网世界中,验证码系统(CAPTCHA)已成为Web安全体系中不可或缺的一环。它通过要求用户完成特定的人机交互任务(如识别图像、拖动滑块或输入随机字符),有效区分“人类用户”与“自动化程序”,从而防止机器人攻击、暴力破解、垃圾信息泛滥等安全威胁。

然而,随着技术的发展,传统的验证码机制正面临双重挑战:

  1. 安全性问题:简单文本验证码可能被OCR技术识别,甚至被AI模型破解;
  2. 用户体验问题:复杂的验证码可能增加用户操作成本,尤其在移动端场景下。

因此,如何在安全性与用户体验之间取得平衡,成为开发者设计验证码系统时的核心考量。本文将以 Spring Boot + Hutool 为核心技术栈,手把手带你构建一个可配置、易扩展、安全可靠的验证码系统,涵盖从基础生成逻辑到高级安全优化的全流程实践。


为什么选择 Spring Boot 与 Hutool?

  • Spring Boot
    作为企业级微服务开发的首选框架,Spring Boot 提供了快速构建REST API、Session管理、自动配置等能力,开发者无需关注复杂的底层配置,即可快速实现验证码接口的开发与集成。
  • Hutool
    作为一款轻量级工具库,Hutool 提供了 CaptchaUtil 工具类,封装了多种验证码类型的生成逻辑(如线条验证码、干扰线验证码等),开发者仅需一行代码即可生成验证码图片,大幅降低开发难度。

本文涵盖的核心内容

  1. 验证码原理与实现
    • 验证码生成流程解析
    • 验证码校验逻辑设计
    • Session存储与过期机制
  2. 配置中心化管理
    • 通过 @ConfigurationProperties 统一管理验证码参数(如宽度、高度、Session键名)
    • 支持动态调整配置,无需修改代码
  3. 安全性增强实践
    • 避免验证码明文记录日志
    • 防止Session键名硬编码
    • 限制请求频率,抵御暴力攻击
  4. 性能优化与扩展
    • HTTP缓存控制策略
    • 异常处理与JSON错误响应
    • 支持滑块验证码、数学题验证码等复杂类型

适用读者

  • Java开发者:熟悉Spring Boot基础,希望快速实现验证码功能。
  • 安全工程师:关注Web应用安全机制,需了解验证码系统的防御逻辑。
  • 架构师:寻求轻量级验证码方案,或需在分布式系统中扩展验证码服务。

通过本文的学习,你将掌握:

  • 如何在Spring Boot中快速集成验证码生成功能;
  • 如何通过配置文件灵活调整验证码参数;
  • 如何提升验证码系统的安全性与健壮性;
  • 如何扩展支持滑块验证码等现代验证方式。

让我们从零开始,构建一个既能抵御攻击、又兼顾用户体验的验证码系统。


 

🧩 一、项目背景与技术选型

1.1 为什么需要验证码?

验证码(CAPTCHA)是一种人机识别机制,通过将随机生成的字符串转换为图片、数学题或滑块等形式,强制用户手动输入以证明自己是“人类”。它的核心目标是防止自动化程序滥用系统资源,保护Web应用免受恶意攻击。以下是其典型应用场景及作用解析:


1. 登录/注册:防止暴力破解与账号盗用

  • 问题:攻击者可通过自动化脚本暴力尝试账号密码组合,窃取用户数据。
  • 解决方案:在登录/注册页面加入验证码,强制人工验证,阻断自动化工具。
  • 示例:若用户连续输错密码超过阈值,系统弹出验证码验证窗口,防止脚本无限尝试。

2. 表单提交:过滤垃圾信息

  • 问题:恶意脚本可批量提交虚假表单(如注册、反馈、报名等),污染数据库。
  • 解决方案:在表单提交时要求验证码验证,确保提交者为真实用户。
  • 示例:企业官网的“联系销售”表单加入验证码,避免被机器人填充广告内容。

3. 评论系统:抵御刷评论与SEO攻击

  • 问题:机器人可批量发布垃圾评论,影响用户体验并干扰搜索排名。
  • 解决方案:在评论提交前要求验证码验证,降低自动化刷评论成功率。
  • 示例:博客平台要求用户输入验证码后才能发布评论,防止水军刷屏。

4. 防止爬虫:限制高频数据抓取

  • 问题:爬虫程序可高频访问网站,窃取数据或导致服务器过载。
  • 解决方案:在敏感接口或高频访问路径中加入验证码,阻断自动化爬虫。
  • 示例:电商网站在商品详情页加入验证码,防止竞争对手批量抓取价格数据。

5. 支付/交易确认:保障资金安全

  • 问题:攻击者可能通过模拟支付流程发起中间人攻击或伪造交易。
  • 解决方案:在支付确认环节加入动态验证码,确保操作由用户主动发起。
  • 示例:银行转账时需输入短信验证码+图形验证码双重验证,提升安全性。

6. 投票/抽奖活动:防止刷票与作弊

  • 问题:机器人可批量注册账号参与活动,破坏公平性。
  • 解决方案:在投票或抽奖接口中加入验证码,确保每次操作由真实用户完成。
  • 示例:线上投票活动要求用户输入验证码后才能提交投票,防止脚本刷票。

验证码的类型与适用场景

验证码类型特点适用场景
文本验证码简单易实现,但可能被OCR识别基础登录、注册
图形验证码更复杂,抗OCR能力强,但对移动端友好性较低金融、支付等高安全需求场景
滑块验证码用户体验好,依赖行为分析,难以被自动化工具破解移动端应用、现代Web平台
数学题验证码简单直观,适合低文化用户群体教育类网站、老年人友好界面
短信/邮件验证码结合手机号或邮箱验证,安全性高,但依赖第三方服务注册、找回密码、支付确认

验证码的局限性与挑战

  1. 用户体验问题:频繁或复杂的验证码会增加用户操作成本,尤其在移动端。
  2. 安全性风险:简单验证码可能被OCR技术识别(如Hacker利用AI训练模型破解)。
  3. 无障碍挑战:视障用户可能无法使用传统图形验证码,需提供语音验证码等替代方案。
  4. 维护成本:需定期更新验证码算法,防止被逆向工程。

现代验证码技术趋势

  • 无感验证码:通过行为分析(如鼠标轨迹、点击模式)判断是否为人类,无需手动输入。
    (如 Google reCAPTCHA v3 返回风险评分,后台自动处理高风险请求)
  • 多因素认证:结合验证码+短信/邮件验证,提升安全性。
  • AI对抗AI:利用机器学习生成更复杂的验证码,同时检测自动化工具特征。

1.2 技术栈选择

在实现验证码功能时,技术选型需兼顾开发效率、功能完整性、系统性能可维护性。本文采用以下技术栈:


1. Spring Boot:企业级微服务开发的首选框架

选型理由

  • 快速构建服务:Spring Boot 提供自动配置(Auto-Configuration)和起步依赖(Starter Dependency),开发者无需手动配置复杂的 XML 或 JavaBean,即可快速启动 Web 服务。
  • 生态丰富:整合了 Spring MVC、Spring Security、Spring Data 等模块,便于后续扩展(如登录安全控制、数据库集成)。
  • 内嵌容器:内置 Tomcat、Jetty 等 Web 容器,无需额外部署,简化开发与测试流程。
  • 标准化 REST API:通过 @RestController@RequestMapping 注解,轻松实现前后端分离的接口设计。

适用场景

  • 需要快速搭建验证服务的中小型项目。
  • 后续可能集成更多功能(如登录、权限控制)的系统。

对比其他方案

  • 传统 Spring MVC:需手动配置 DispatcherServlet、ViewResolver 等组件,开发效率较低。
  • Go/Python 微框架:虽然性能更高,但生态和社区成熟度不如 Spring Boot,学习成本较高。

2. Hutool:轻量级工具库,简化验证码生成

选型理由

  • 一站式工具类:Hutool 提供 CaptchaUtil 工具类,封装了验证码生成的核心逻辑(如图像绘制、干扰线添加、Base64 编码输出),开发者仅需一行代码即可生成验证码。
  • 支持多种类型:提供 LineCaptcha(线条验证码)、ShearCaptcha(干扰线验证码)、CircleCaptcha(圆形干扰验证码)等,满足不同安全等级需求。
  • 低依赖性:仅需引入 hutool-all 依赖,无需额外配置,适合轻量级项目。

示例代码

LineCaptcha captcha = CaptchaUtil.createLineCaptcha(200, 100); // 生成200x100像素的线条验证码
String code = captcha.getCode(); // 获取验证码文本
captcha.write(response.getOutputStream()); // 将图片写入响应流

对比其他方案

  • Java 原生 BufferedImage:需手动绘制图像、添加干扰元素,代码复杂且易出错。
  • Kaptcha:功能强大但配置繁琐,需通过 XML 定义样式,灵活性较低。
  • Google reCAPTCHA:依赖第三方服务,需联网验证,不适合内网或离线场景。

3. Session:轻量级验证码存储方案

选型理由

  • 无数据库压力:验证码生命周期短(通常为1~5分钟),若存储至数据库需频繁增删记录,增加 I/O 开销;而 Session 基于内存存储,读写速度快。
  • 天然集成 Spring:Spring Boot 默认支持 Session 管理(如 HttpSession),开发者无需额外引入缓存中间件(如 Redis)。
  • 安全性可控:Session ID 由服务器生成并加密,客户端仅保存 Session ID,避免敏感信息泄露。

示例代码

session.setAttribute("CAPTCHA_CODE", code); // 存储验证码文本
session.setAttribute("CAPTCHA_TIME", System.currentTimeMillis()); // 存储生成时间

适用场景

  • 单机部署或小型系统,无需跨服务共享 Session。
  • 对实时性要求高、数据量小的临时存储场景(如验证码、登录状态)。

对比其他方案

  • 数据库存储:适合长期存储,但验证码过期后需清理,维护成本高。
  • Redis 缓存:支持分布式部署和持久化,但需额外部署 Redis 服务,适合中大型系统。
  • Cookie 存储:直接暴露验证码值,易被篡改,存在安全风险。

技术栈协同工作流程

  1. 请求验证码生成

    • 前端调用 /getCaptcha 接口 →
    • Spring Boot Controller 调用 Hutool 生成验证码图片 →
    • 将验证码文本和生成时间存入 Session →
    • 图片通过 HTTP 响应流返回给前端。
  2. 提交表单验证

    • 用户输入验证码并提交 →
    • Spring Boot Controller 从 Session 中获取原始验证码 →
    • 比对用户输入与原始值,并检查是否过期 →
    • 返回校验结果(成功/失败)。

总结

技术优势适用场景
Spring Boot快速开发、生态丰富、标准化接口快速搭建微服务,集成多模块功能
Hutool简化验证码生成,支持多种类型轻量级验证码需求,避免重复造轮子
Session低延迟、无依赖、安全性可控单机部署下的临时数据存储

该技术栈组合兼顾开发效率系统性能,适合中小型项目或快速原型开发。若需支持分布式部署,可将 Session 替换为 Redis 实现共享存储。

 

🛠️ 二、项目搭建与依赖配置

2.1 Maven 依赖

<dependencies><!-- Spring Boot Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Hutool 工具库 --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.22</version></dependency>
</dependencies>

2.2 配置文件(application.properties)

# 验证码配置
captcha.width=120
captcha.height=40
captcha.session.key=CAPTCHA_CODE
captcha.session.time=CAPTCHA_TIME

🎨 三、验证码生成逻辑详解

3.1 配置类:CaptchaProperties

@Component
@ConfigurationProperties(prefix = "captcha")
public class CaptchaProperties {private int width;private int height;private Session session = new Session();public static class Session {private String key;private String time;// Getter & Setter}// Getter for sessionpublic Session getSession() {return session;}
}
  • 作用:将 application.properties 中的配置映射到 Java 对象。
  • 关键注解@ConfigurationProperties 实现松散绑定(如 captcha.session.key 映射到 session.key)。

3.2 控制器:CaptchaController

@RestController
public class CaptchaController {private static final long VALID_TIMEOUT = 60 * 1000; // 1分钟有效期@Autowiredprivate CaptchaProperties captchaProperties;@GetMapping("/getCaptcha")public void getCaptcha(HttpSession session, HttpServletResponse response) throws IOException {LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(captchaProperties.getWidth(), captchaProperties.getHeight());String code = lineCaptcha.getCode();// 存储验证码和生成时间到Sessionsession.setAttribute(captchaProperties.getSession().getKey(), code);session.setAttribute(captchaProperties.getSession().getTime(), System.currentTimeMillis());// 设置响应头response.setContentType("image/jpeg");response.setHeader("Pragma", "No-cache");response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");response.setDateHeader("Expires", 0);// 写入图片到响应流lineCaptcha.write(response.getOutputStream());}
}
  • 核心逻辑
    1. 使用 Hutool 生成线条验证码。
    2. 将验证码文本和生成时间存入 Session。
    3. 通过 response.getOutputStream() 将图片数据写入 HTTP 响应流,不存储在服务器端
    4. 设置响应头禁止缓存,确保每次请求生成新验证码。

 

🔍 四、验证码校验逻辑实现

4.1 校验接口

@PostMapping("/check")
public boolean checkCaptcha(@RequestParam String captcha, HttpSession session) {if (!StringUtils.hasText(captcha)) {return false;}String storedCode = (String) session.getAttribute(captchaProperties.getSession().getKey());Long timestamp = (Long) session.getAttribute(captchaProperties.getSession().getTime());if (storedCode == null || timestamp == null) {return false;}// 判断是否过期if (System.currentTimeMillis() - timestamp > VALID_TIMEOUT) {session.removeAttribute(captchaProperties.getSession().getKey());session.removeAttribute(captchaProperties.getSession().getTime());return false;}return captcha.equalsIgnoreCase(storedCode);
}
  • 校验流程
    1. 检查用户输入是否为空。
    2. 从 Session 获取原始验证码和生成时间。
    3. 判断验证码是否过期(默认1分钟)。
    4. 忽略大小写比对用户输入与原始验证码。

⚠️ 五、安全性与优化建议

在实现验证码功能时,除了基础功能外,还需重点关注安全性与系统健壮性。以下是针对验证码生成与校验环节的常见问题及优化方向:


5.1 安全性注意事项

问题风险建议解决方案
验证码明文记录日志日志文件可能泄露敏感信息,攻击者可通过日志获取有效验证码。- 避免打印验证码内容:仅记录日志提示(如“验证码已生成”),不输出 code 值。
Session 键名硬编码键名分散在代码中,维护困难且易引发冲突。- 统一配置管理:通过 CaptchaProperties 配置类集中管理 Session 键名。
验证码复杂度不足简单验证码易被 OCR 识别或自动化工具破解(如 LineCaptcha)。- 替换为复杂类型:使用 ShearCaptcha(干扰线验证码)或滑块验证码。
未限制请求频率攻击者可高频请求 /getCaptcha 接口,导致服务器资源耗尽或暴力破解验证码。- 请求频率限制:结合 Redis 或拦截器,限制同一 IP/Session 的请求频率。

5.2 优化建议

1. 缓存控制增强

问题:浏览器可能缓存旧验证码图片,导致用户看到过期内容。
解决方案
在生成验证码时设置 HTTP 响应头,禁止缓存:

response.setContentType("image/jpeg");
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setDateHeader("Expires", 0);
  • 效果:确保每次请求都生成新验证码,避免浏览器使用缓存图片。

2. 异常处理完善

问题:生成验证码时若抛出 IOException,直接抛出 RuntimeException 会导致前端无法友好处理错误。
解决方案
捕获异常并返回 JSON 错误信息:

@GetMapping("/getCaptcha")
public void getCaptcha(HttpSession session, HttpServletResponse response) {try {LineCaptcha captcha = CaptchaUtil.createLineCaptcha(200, 100);session.setAttribute("CAPTCHA_CODE", captcha.getCode());response.setContentType("image/jpeg");captcha.write(response.getOutputStream());} catch (IOException e) {logger.error("验证码生成失败", e);response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);try (PrintWriter writer = response.getWriter()) {writer.write("{\"error\": \"验证码生成失败\"}");} catch (IOException ex) {logger.error("写入错误响应失败", ex);}}
}
  • 效果:前端可捕获错误并提示用户重试,提升用户体验。

3. 验证码类型扩展

问题:单一验证码类型(如 LineCaptcha)安全性较低。
解决方案
支持多种验证码类型,根据场景动态选择:

// 使用 ShearCaptcha(干扰线验证码)
ShearCaptcha shearCaptcha = CaptchaUtil.createShearCaptcha(200, 100, 4, 4);
session.setAttribute("CAPTCHA_CODE", shearCaptcha.getCode());
shearCaptcha.write(response.getOutputStream());// 使用滑块验证码(需前端配合)
// 示例:通过 Base64 返回滑块图片
String base64 = shearCaptcha.getImageBase64();
response.getWriter().write("{\"image\": \"" + base64 + "\"}");
  • 效果:提升安全性,支持移动端友好交互(如滑块验证码)。

4. 请求频率限制(防暴力攻击)

问题:攻击者可通过高频请求 /getCaptcha/check 接口尝试破解验证码。
解决方案
使用 Redis 记录请求次数,限制单位时间内的请求频率:

@Autowired
private RedisTemplate<String, Integer> redisTemplate;private static final String CAPTCHA_REQUEST_KEY = "captcha:request:ip:";
private static final int MAX_REQUESTS_PER_MINUTE = 10;public boolean isRequestAllowed(String ip) {String key = CAPTCHA_REQUEST_KEY + ip;Integer count = redisTemplate.opsForValue().get(key);if (count == null) {redisTemplate.opsForValue().set(key, 1, 1, TimeUnit.MINUTES);return true;} else if (count < MAX_REQUESTS_PER_MINUTE) {redisTemplate.opsForValue().increment(key);return true;}return false;
}
  • 效果:防止攻击者高频请求接口,保护系统资源。

5. Session 安全管理

问题:验证码长期存储在 Session 中,可能占用内存或被复用。
解决方案

  • 及时清理过期验证码:在校验成功或失败后删除 Session 中的验证码:
    session.removeAttribute("CAPTCHA_CODE");
    session.removeAttribute("CAPTCHA_TIME");
    
  • 设置 Session 过期时间:在 application.properties 中配置:
    server.servlet.session.timeout=1m
    

6. 日志与监控

问题:缺乏对异常行为的监控,无法及时发现攻击。
解决方案

  • 记录关键操作日志:如验证码生成、校验失败等:
    logger.info("验证码校验失败:用户输入={}, 正确值={}", userCode, storedCode);
    
  • 集成监控系统:使用 Prometheus + Grafana 监控验证码请求频率和失败率。

总结:安全与优化要点

优化方向具体措施
日志安全避免记录验证码明文,仅记录操作日志(如“验证码生成成功/失败”)。
配置管理通过 @ConfigurationProperties 统一管理 Session 键名、验证码类型等参数。
验证码复杂度使用 ShearCaptcha 或滑块验证码,提升 OCR 破解难度。
请求频率控制结合 Redis 或拦截器限制 /getCaptcha/check 的请求频率。
异常处理捕获 IOException 并返回 JSON 错误信息,避免暴露堆栈信息。
缓存控制设置 HTTP 响应头禁止缓存,确保每次请求生成新验证码。
Session 管理校验后及时清理 Session,避免内存泄漏。
监控与告警记录关键日志并接入监控系统,实时检测异常行为。

通过以上措施,可显著提升验证码系统的安全性与稳定性,有效防御自动化攻击,同时优化用户体验。

 

📦 六、完整代码结构示例

src/
├── main/
│   ├── java/
│   │   └── com.example.captcha/
│   │       ├── config/CaptchaProperties.java
│   │       ├── controller/CaptchaController.java
│   │       └── DemoApplication.java
│   └── resources/
│       └── application.properties

📝 七、总结

本文基于 Spring Boot + Hutool 实现了一个完整且可扩展的验证码生成与校验系统,覆盖了从基础功能到安全性优化的全流程。以下是核心内容的归纳与延伸思考:


1. 核心功能实现

  • 验证码生成原理
    通过 CaptchaUtil 工具类快速生成验证码图片(如 LineCaptchaShearCaptcha),结合 HTTP 响应流将图片数据直接传输至客户端,避免服务器端存储。

  • 配置中心化管理
    使用 @ConfigurationProperties 将验证码参数(如宽度、高度、Session键名)集中管理,通过 application.properties 统一配置,提升可维护性与灵活性。

  • 验证码校验逻辑
    利用 Session 存储验证码文本及生成时间,结合时间戳判断过期状态,最终通过忽略大小写的字符串比对完成校验。


2. 安全性与优化实践

  • 风险防控

    • 日志安全:避免记录验证码明文,仅输出操作日志(如“验证码生成成功”)。
    • Session 管理:统一配置 Session 键名,校验后及时清理过期数据,防止内存泄漏。
    • 请求频率限制:结合 Redis 限制 /getCaptcha/check 接口的请求频率,抵御暴力攻击。
  • 性能优化

    • 缓存控制:设置 HTTP 响应头(Cache-ControlExpires)禁止浏览器缓存验证码图片,确保每次请求生成新内容。
    • 异常处理:捕获 IOException 并返回结构化 JSON 错误信息,提升前后端交互的健壮性。
    • 多类型支持:扩展滑块验证码、数学题验证码等复杂类型,适配移动端与高安全场景。

3. 应用场景与扩展方向

  • 典型应用场景

    • 登录/注册:防止暴力破解,保护用户账户安全。
    • 表单提交:过滤垃圾信息,保障数据质量。
    • 支付确认:结合短信/邮件验证码,实现多因素认证。
    • 防爬虫:限制高频访问,保护敏感数据接口。
  • 未来扩展建议

    • 分布式支持:将 Session 替换为 Redis,实现跨服务共享验证码状态。
    • 前端协作优化:支持 Base64 图片嵌入与滑块轨迹验证,提升用户体验。
    • AI对抗设计:利用机器学习生成动态干扰模式,增强 OCR 破解难度。
    • 监控集成:通过 Prometheus + Grafana 实时监控验证码请求量与失败率,辅助安全分析。

4. 技术价值与适用性

  • Spring Boot 的优势
    快速构建微服务,集成 REST API 与 Session 管理,降低开发复杂度。
  • Hutool 的价值
    提供开箱即用的验证码工具类,避免重复造轮子,适合轻量级项目。
  • 适用场景
    适用于中小型系统、快速原型开发,或需灵活扩展验证码类型的场景。

5. 结语

验证码系统是 Web 安全体系中的重要一环,但并非孤立存在。通过本文的实现方案,开发者可以快速构建一个安全可靠、易于维护、可扩展性强的验证码服务。未来可根据业务需求进一步引入滑块验证、行为分析等高级机制,持续提升系统的安全性与用户体验。

代码即安全,设计即防御——从基础功能到深度优化,验证码系统的每一层设计都关乎系统的整体健壮性。希望本文能为你的项目实践提供实用参考!

 

相关文章:

  • 并发与并行的关系
  • 如何防止域名DNS被劫持?
  • 【Go】优化文件下载处理:从多级复制到零拷贝流式处理
  • 极狐GitLab 容器镜像仓库功能介绍
  • 电池分压电阻检测不准的原因
  • AI日报 · 2025年5月08日|Stripe发布全球首个支付AI基础模型
  • 山东136号文实施方案与竞价细则
  • Ubuntu18.04 设置开机服务自启
  • 关于ubuntu下交叉编译arrch64下的gtsam报错问题,boost中boost_regex.so中连接libicui18n.so.55报错的问题
  • 移植easylogger通过J-Linker的RTT输出日志/Ozone的RTT设置
  • sui在windows虚拟化子系统Ubuntu和纯windows下的安装和使用
  • 【嵌入式开发-USB】
  • RabbitMQ--基础篇
  • Crawl4AI:高效的开源 Python 网页爬取与数据提取库
  • 【5G通信】redcap和bwp 随手记
  • 论文速读《DARE:基于扩散模型的自主机器人探索新范式》
  • debian12 安装docker
  • 多模态大语言模型arxiv论文略读(六十四)
  • 美团二面:使用分布式调度框架该考虑哪些问题?
  • 【Java ee 初阶】文件IO和操作(下)
  • 河南省平顶山市副市长许红兵主动投案,接受审查调查
  • 如此城市|上海老邬:《爱情神话》就是我生活的一部分
  • 大四本科生已发14篇SCI论文?学校工作人员:已记录汇报
  • 谜语的强制力:弗洛伊德与俄狄浦斯
  • 小米回应SU7Ultra排位模式限制车辆动力:暂停推送更新
  • 人民日报钟声:中方维护自身发展利益的决心不会改变