SpringBoot实战:从零构建一个带Session验证的登录系统(附完整前后端源码)
1. 项目概述与核心目标这个实战项目将带你从零构建一个基于SpringBoot的登录系统重点在于理解Session验证机制在前后端分离模式下的应用。想象一下你正在开发一个需要用户认证的小型应用比如个人博客后台而登录功能是所有交互的起点。通过这个麻雀虽小五脏俱全的项目你将掌握前后端数据交互的基本流程Session在用户身份验证中的核心作用如何安全地存储和验证用户凭证完整的项目结构设计与代码组织我会使用最简洁的技术栈SpringBoot 原生HTML/JQuery来降低学习门槛但实现的是企业级登录验证的核心逻辑。所有代码都经过实际验证你可以在文末获取完整源码。2. 环境准备与项目创建2.1 开发工具要求确保你的开发环境包含JDK 1.8或更高版本IntelliJ IDEA推荐或EclipseMaven 3.6现代浏览器Chrome/Firefox2.2 创建SpringBoot项目通过Spring Initializr快速初始化项目访问 start.spring.io选择Project: MavenLanguage: JavaSpring Boot: 2.7.x添加依赖Spring WebThymeleaf可选用于模板渲染或者直接用IDEA的Spring Initializr向导创建。初始化后的pom.xml应该包含dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency /dependencies2.3 项目结构规划创建以下目录结构部分目录SpringBoot会自动生成src/ ├── main/ │ ├── java/ │ │ └── com/example/logindemo/ │ │ ├── controller/ # 控制器 │ │ ├── config/ # 配置类 │ │ └── LoginDemoApplication.java │ └── resources/ │ ├── static/ # 静态资源 │ │ ├── css/ │ │ ├── js/ │ │ └── images/ │ ├── templates/ # 模板文件 │ └── application.properties3. 前端页面开发3.1 登录页面(login.html)在resources/static下创建登录页面!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title用户登录/title script srchttps://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js/script style .login-form { width: 300px; margin: 100px auto; padding: 20px; border: 1px solid #ddd; border-radius: 5px; } .form-group { margin-bottom: 15px; } .form-group label { display: block; margin-bottom: 5px; } .form-group input { width: 100%; padding: 8px; box-sizing: border-box; } .submit-btn { width: 100%; padding: 10px; background: #1890ff; color: white; border: none; border-radius: 4px; cursor: pointer; } /style /head body div classlogin-form h2用户登录/h2 div classform-group label用户名/label input typetext iduserName placeholder请输入用户名 /div div classform-group label密码/label input typepassword idpassword placeholder请输入密码 /div button classsubmit-btn onclicklogin()登录/button /div script function login() { const username $(#userName).val(); const password $(#password).val(); if(!username || !password) { alert(用户名和密码不能为空); return; } $.ajax({ url: /user/login, type: POST, contentType: application/json, data: JSON.stringify({ userName: username, password: password }), success: function(result) { if(result.success) { window.location.href /index.html; } else { alert(登录失败: result.message); } }, error: function(xhr) { alert(请求异常: xhr.statusText); } }); } /script /body /html3.2 主页(index.html)创建简单的主页用于展示登录状态!DOCTYPE html html langzh-CN head meta charsetUTF-8 title系统主页/title script srchttps://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js/script /head body h1欢迎访问系统/h1 div 当前登录用户: span idloginUser/span button onclicklogout() stylemargin-left: 20px;退出登录/button /div script // 页面加载时获取用户信息 $(document).ready(function() { $.get(/user/getUserInfo, function(username) { if(username) { $(#loginUser).text(username); } else { alert(未登录或会话已过期); window.location.href /login.html; } }); }); function logout() { $.post(/user/logout, function() { window.location.href /login.html; }); } /script /body /html4. 后端核心实现4.1 用户控制器(UserController)创建处理登录逻辑的核心控制器package com.example.logindemo.controller; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; RestController RequestMapping(/user) public class UserController { // 模拟用户数据实际项目应从数据库获取 private static final String VALID_USERNAME admin; private static final String VALID_PASSWORD 123456; PostMapping(/login) public Result login(RequestBody LoginRequest request, HttpServletRequest httpRequest) { // 参数校验 if (!StringUtils.hasText(request.getUserName()) || !StringUtils.hasText(request.getPassword())) { return Result.fail(用户名和密码不能为空); } // 验证凭证实际项目应使用加密验证 if (VALID_USERNAME.equals(request.getUserName()) VALID_PASSWORD.equals(request.getPassword())) { // 创建会话 HttpSession session httpRequest.getSession(); session.setAttribute(username, request.getUserName()); session.setMaxInactiveInterval(30 * 60); // 30分钟过期 return Result.success(登录成功); } return Result.fail(用户名或密码错误); } GetMapping(/getUserInfo) public String getUserInfo(HttpSession session) { // 从会话中获取用户名 String username (String) session.getAttribute(username); if (username null) { throw new RuntimeException(未登录或会话已过期); } return username; } PostMapping(/logout) public Result logout(HttpSession session) { // 使会话失效 session.invalidate(); return Result.success(退出成功); } // 内部类登录请求体 public static class LoginRequest { private String userName; private String password; // getters and setters } // 简单结果封装 public static class Result { private boolean success; private String message; // 静态工厂方法 public static Result success(String message) { return new Result(true, message); } public static Result fail(String message) { return new Result(false, message); } // constructor and getters } }4.2 Session配置优化在application.properties中添加Session配置# Session配置 server.servlet.session.timeout1800 # 30分钟(单位秒) server.servlet.session.cookie.nameLOGIN_SESSION server.servlet.session.cookie.http-onlytrue # 防止XSS server.servlet.session.cookie.securefalse # 开发环境可关闭生产环境应开启对于更复杂的场景可以创建WebConfig配置类Configuration public class WebConfig implements WebMvcConfigurer { Bean public ServletWebServerFactory servletContainer() { TomcatServletWebServerFactory factory new TomcatServletWebServerFactory(); factory.addErrorPages(new ErrorPage(HttpStatus.UNAUTHORIZED, /error/401)); return factory; } }5. 安全增强与最佳实践5.1 密码加密存储实际项目中绝对不要明文存储密码使用BCrypt加密添加依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-security/artifactId /dependency创建密码工具类import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; public class PasswordUtil { private static final BCryptPasswordEncoder encoder new BCryptPasswordEncoder(); public static String encode(String rawPassword) { return encoder.encode(rawPassword); } public static boolean matches(String rawPassword, String encodedPassword) { return encoder.matches(rawPassword, encodedPassword); } }5.2 防御CSRF攻击虽然我们的简单示例没有使用CSRF保护但在生产环境中应该启用Configuration EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { Override protected void configure(HttpSecurity http) throws Exception { http .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED); } }5.3 登录失败处理增强登录接口的安全性PostMapping(/login) public Result login(RequestBody LoginRequest request, HttpServletRequest httpRequest) { // 添加登录失败次数限制 HttpSession session httpRequest.getSession(); Integer attemptCount (Integer) session.getAttribute(loginAttempts); if (attemptCount null) { attemptCount 0; } if (attemptCount 3) { return Result.fail(尝试次数过多请稍后再试); } // ...验证逻辑... if (!VALID_USERNAME.equals(request.getUserName()) || !VALID_PASSWORD.equals(request.getPassword())) { session.setAttribute(loginAttempts, attemptCount); return Result.fail(用户名或密码错误); } // 登录成功重置计数器 session.removeAttribute(loginAttempts); // ...其他逻辑... }6. 项目测试与调试6.1 测试登录流程启动应用运行LoginDemoApplication访问http://localhost:8080/login.html测试用例正确凭证admin/123456错误凭证观察提示信息直接访问index.html应重定向到登录页6.2 使用Postman测试API创建以下请求集合登录请求Method: POSTURL:http://localhost:8080/user/loginBody (raw/JSON):{ userName: admin, password: 123456 }检查响应中的Set-Cookie头获取用户信息Method: GETURL:http://localhost:8080/user/getUserInfo添加Cookie: LOGIN_SESSION你的sessionId6.3 常见问题排查Session不持久检查浏览器是否禁用Cookie跨域问题确保前端和后端同源或配置CORS静态资源404确认文件放在resources/static目录响应时间过长检查Session存储配置默认使用内存7. 项目扩展方向这个基础版本可以进一步扩展数据库集成使用Spring Data JPA连接MySQL创建User实体和Repository记住我功能使用持久化Cookie实现长期登录结合Token机制验证码支持集成Google Kaptcha或使用Hutool工具生成简单验证码OAuth2.0集成支持GitHub/微信等第三方登录使用Spring Security OAuth前端框架整合替换原生HTML为Vue/React使用Axios替代JQuery Ajax完整项目源码已托管在GitHub包含所有配置和扩展示例。通过这个项目你不仅学会了Session验证的实现更重要的是理解了Web认证的核心流程。在实际开发中可以根据需求组合不同的安全机制构建更健壮的认证系统。

相关新闻

GNU Radio快速原型设计:活用Embedded Python Block实现信号处理

GNU Radio快速原型设计:活用Embedded Python Block实现信号处理

1. Embedded Python Block:信号处理原型的瑞士军刀第一次接触GNU Radio时,我被它复杂的C模块编译流程劝退了好几次。直到发现Embedded Python Block这个神器,才真正体会到快速原型设计的快感。这就像突然从手工锻造铁器的时代,进化…

2026/7/18 12:24:11
UI设计智能体工作流:用Codex+ui-ux-pro-max降低AI页面返工率

UI设计智能体工作流:用Codex+ui-ux-pro-max降低AI页面返工率

1. 这不是又一个提示词模板,而是一套可落地的UI设计智能体工作流最近在出海圈里,只要聊到“怎么让AI生成的页面不那么像AI做的”,几乎所有人都会提到一个名字:ui-ux-pro-max。它不是某个大厂推出的闭源工具,也不是某位…

2026/7/22 1:53:32
STM32CubeMX实战:基于FatFS与FreeRTOS的U盘数据采集与存储系统

STM32CubeMX实战:基于FatFS与FreeRTOS的U盘数据采集与存储系统

1. 系统架构设计 这个基于STM32的数据采集系统核心在于 多任务协同 和 稳定存储 。我通常会把它拆解成三个关键部分:传感器数据采集层、实时操作系统调度层、以及文件系统存储层。用个生活化的比喻——就像一家餐厅的后厨运作:传感器是负责备菜的厨师…

2026/7/22 7:42:00

最新新闻

JetBrains Air IDE:面向AI原生开发的容器化IDE架构

JetBrains Air IDE:面向AI原生开发的容器化IDE架构

1. JetBrains Air IDE 是什么?不是“又一个AI IDE”,而是IDE架构的范式迁移JetBrains Air IDE 这个名字刚出来时,我第一反应是:又一个套着AI外壳的玩具产品?毕竟过去两年,“AI IDE”这个词已经被各种创业公…

2026/7/22 5:44:04
从PEP 517到wheel构建:深入解析bottleneck安装失败的根本原因与系统化修复

从PEP 517到wheel构建:深入解析bottleneck安装失败的根本原因与系统化修复

1. 当Python遇上C扩展:bottleneck安装失败背后的技术困局 那天下午,我正在为一个时间序列分析项目配置环境。当执行 pip install bottleneck 时,熟悉的红色错误提示突然跳出:"ERROR: Could not build wheels for bottlenec…

2026/7/22 5:42:03
Swindler事件系统详解:如何监听并响应窗口状态变化

Swindler事件系统详解:如何监听并响应窗口状态变化

Swindler事件系统详解:如何监听并响应窗口状态变化 【免费下载链接】Swindler macOS window management library for Swift 项目地址: https://gitcode.com/gh_mirrors/sw/Swindler Swindler是一款强大的macOS窗口管理Swift库,提供了全面的事件系…

2026/7/22 5:42:20
CANN/asc-devkit绝对值计算API

CANN/asc-devkit绝对值计算API

asc_abs 【免费下载链接】asc-devkit 本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言,原生支持C和C标准规范,主要由类库和语言扩展层构成,提供多层级API,满足多维场景算子开发诉求。 项目地址: https://gitcode.com/ca…

2026/7/22 5:41:48
CANN/ops-sparse稀疏算子开发指南

CANN/ops-sparse稀疏算子开发指南

{算子名称}算子 【免费下载链接】ops-sparse 本项目是CANN提供的高性能稀疏矩阵计算的算子库,专注于优化稀疏矩阵的计算效率。 项目地址: https://gitcode.com/cann/ops-sparse 算子概述 {一段话描述算子的功能定位和核心运算。例如:"{op} 算…

2026/7/22 5:42:31
MATLAB工具箱实战:从零安装CVX到解决首个凸优化问题

MATLAB工具箱实战:从零安装CVX到解决首个凸优化问题

1. CVX工具箱简介与安装准备CVX是一个专门用于解决凸优化问题的MATLAB工具箱,它能让用户用接近数学表达式的语法来描述和求解优化问题。我第一次接触CVX是在研究生阶段做信号处理项目时,当时需要解决一个复杂的投资组合优化问题,传统方法代码…

2026/7/22 5:43:41

日新闻

周新闻

月新闻