前言

最近通过一个皮肤信息管理系统的项目实践,深入学习了Spring Boot框架中登录认证功能的实现方式。这个项目涵盖了从后端配置到前端集成的完整流程,让我对现代Web应用的安全机制有了更深刻的理解。本文将分享我在这个过程中的学习心得和技术要点。

一、JWT认证机制的理解与实现

1.1 为什么选择JWT

传统的Session认证方式在分布式系统中存在扩展性问题,而JWT(JSON Web Token)作为一种无状态的认证机制完美解决了这个问题。在项目中,我们采用了JWT来实现用户认证,主要优势在于:

  • ​无状态​​:服务端不需要存储会话信息
  • ​跨域支持​​:适合前后端分离架构
  • ​自包含​​:所有必要信息都包含在token中

1.2 JWT工具类实现

@Component
public class JwtUtils {private static final String SECRET = "your-secret-key";private static final long EXPIRATION = 86400000L; // 24小时public static String generateToken(UserDetails userDetails) {return Jwts.builder().setSubject(userDetails.getUsername()).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + EXPIRATION)).signWith(SignatureAlgorithm.HS512, SECRET).compact();}public static String getUsernameFromToken(String token) {return Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody().getSubject();}public static boolean validateToken(String token, UserDetails userDetails) {final String username = getUsernameFromToken(token);return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));}private static boolean isTokenExpired(String token) {final Date expiration = getExpirationDateFromToken(token);return expiration.before(new Date());}
}

二、Spring Security整合实践

2.1 安全配置类

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService userDetailsService;@Autowiredprivate JwtAuthenticationEntryPoint unauthorizedHandler;@Beanpublic JwtAuthenticationFilter jwtAuthenticationFilter() {return new JwtAuthenticationFilter();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.cors().and().csrf().disable().exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests().antMatchers("/api/auth/**").permitAll().antMatchers("/api/test/**").permitAll().anyRequest().authenticated();http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);}
}

2.2 自定义认证过滤器

public class JwtAuthenticationFilter extends OncePerRequestFilter {@Autowiredprivate JwtUtils jwtUtils;@Autowiredprivate UserDetailsService userDetailsService;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {try {String jwt = parseJwt(request);if (jwt != null && jwtUtils.validateToken(jwt)) {String username = jwtUtils.getUsernameFromToken(jwt);UserDetails userDetails = userDetailsService.loadUserByUsername(username);UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));SecurityContextHolder.getContext().setAuthentication(authentication);}} catch (Exception e) {logger.error("Cannot set user authentication: {}", e);}filterChain.doFilter(request, response);}private String parseJwt(HttpServletRequest request) {String headerAuth = request.getHeader("Authorization");if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) {return headerAuth.substring(7);}return null;}
}

三、前后端交互设计

3.1 登录接口设计

@RestController
@RequestMapping("/api/auth")
public class AuthController {@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate JwtUtils jwtUtils;@PostMapping("/login")public ResponseEntity<?> authenticateUser(@RequestBody LoginRequest loginRequest) {Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));SecurityContextHolder.getContext().setAuthentication(authentication);String jwt = jwtUtils.generateToken(authentication);UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();return ResponseEntity.ok(new JwtResponse(jwt, userDetails.getId(), userDetails.getUsername(), userDetails.getEmail()));}
}

3.2 前端请求处理

在Vue项目中,我们使用axios进行HTTP请求,并配置请求和响应拦截器:

// 请求拦截器
axios.interceptors.request.use(config => {const token = localStorage.getItem('token');if (token) {config.headers['Authorization'] = 'Bearer ' + token;}return config;},error => {return Promise.reject(error);}
);// 响应拦截器
axios.interceptors.response.use(response => {return response.data;},error => {if (error.response.status === 401) {// 处理token过期或无效的情况localStorage.removeItem('token');router.push('/login');}return Promise.reject(error);}
);

更改后的界面如下:

点击注销登录后恢复原来的登录界面则大功告成

四、项目实践中的经验总结

  1. ​安全性考虑​​:

    • 使用HTTPS加密传输
    • 设置合理的token过期时间
    • 敏感操作需要二次验证
    • 密码必须加密存储(BCrypt)
  2. ​性能优化​​:

    • 减少JWT的payload大小
    • 考虑使用Redis缓存用户权限信息
    • 实现token刷新机制,避免频繁登录
  3. ​异常处理​​:

    • 统一的认证异常处理
    • 详细的错误信息返回(但不暴露系统细节)
    • 友好的前端错误提示
  4. ​测试要点​​:

    • 多种场景测试:正确凭证、错误凭证、过期token、无效token
    • 并发请求测试
    • 前后端分离情况下的跨域测试

五、进一步探索方向

  1. ​OAuth2.0集成​​:实现第三方登录功能
  2. ​多因素认证​​:增加短信/邮箱验证码等二次验证
  3. ​权限精细化控制​​:基于RBAC模型的权限管理
  4. ​单点登录(SSO)​​:多系统间的统一认证
  5. ​安全审计​​:记录用户登录日志和敏感操作

结语

通过这个皮肤信息管理系统的登录认证模块实现,我深刻理解了Spring Security和JWT的工作原理,掌握了前后端分离架构下的认证流程设计。这些知识不仅适用于当前项目,也为今后开发更复杂的系统打下了坚实基础。建议初学者可以从这个小而完整的模块入手,逐步扩展到更复杂的安全场景。

​项目完整代码已上传GitHub​​:项目地址

欢迎在评论区交流Spring Boot安全实现的相关问题!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/87862.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/87862.shtml
英文地址,请注明出处:http://en.pswp.cn/web/87862.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【初阶数据结构】双向链表

文章目录 双向链表1.申请节点2.链表初始化3.尾插4.打印链表5.头插6.尾删7.头删8.查找9.指定位置插入10.删除pos节点11.链表的销毁12.程序源码 双向链表 链表分类 8种 (带头/不带头 单向/双向 循环/循环) 最常用两种 单链表(不带头单向不循环链表) 双向链表&#xff08;带头双向…

从 Prompt 管理到人格稳定:探索 Cursor AI 编辑器如何赋能 Prompt 工程与人格风格设计(下)

六、引入 Cursor AI 编辑器的开发流程革新 在整个系统开发过程中&#xff0c;我大量采用了 Cursor 编辑器作为主要的开发环境&#xff0c;并获得以下关键收益&#xff1a; 具备 AI 补全与代码联想功能&#xff1a;支持通过内置 Copilot 模型对 Python、FastAPI、YAML、JSON 等…

Spark运行架构

Spark框架的核心是一个计算引擎&#xff0c;整体来说&#xff0c;它采用了标准master-slave的结构  如下图所示&#xff0c;它展示了一个Spark执行时的基本结构&#xff0c;图形中的Driver表示master&#xff0c;负责管理整个集群中的作业任务调度&#xff0c;图形中的Executo…

基于未合入PR创建增量patch的git管理方法

目录前言准备操作步骤精准移植基础PR到本地分支修改代码鸿蒙编译、调试、测试具体编译指令、测试步骤这里带过&#xff0c;这不是本文论述重点创建diff文件工作仓库应用最新patch总结前言 作为程序员&#xff0c;多人协同开发同一个需求是正常的。即使是自己一个人搞需求&…

git真正更新项目

背景 Fetch all remote后flutter代码都拉下来&#xff0c;都是Android项目应用不上&#xff1b;git–>update project才生效&#xff01;&#xff01;&#xff01;

AI时代如何拓展Web前端开发的边界

文章目录 1 从“页面仔”到“智能体验构建者”——前端的变与不变2 AI 如何重塑 Web 前端&#xff1a;从开发到用户体验的革命2.1 AI 赋能开发效率&#xff1a;前端工程师的“超级外挂”2.1.1 智能代码辅助与生成2.1.2 自动化测试与 Bug 定位 2.2 AI 提升用户体验&#xff0c;构…

chrome webdrive异常处理-session not created falled opening key——仙盟创梦IDE

注册表错误 :EKKOK:chromeinstallerut1 Lgoogle update settings.cc:26b falled opening key .( e\Update\ClientStateMedium 8A69D345-D564-463c-AFF1-A69D9E530F96} to set usagestats 连接超时 disconnected: received Inspector.detached eventfailed to check if windo…

【Java EE初阶 --- 多线程(进阶)】JUC

乐观学习&#xff0c;乐观生活&#xff0c;才能不断前进啊&#xff01;&#xff01;&#xff01; 我的主页&#xff1a;optimistic_chen 我的专栏&#xff1a;c语言 &#xff0c;Java 欢迎大家访问~ 创作不易&#xff0c;大佬们点赞鼓励下吧~ 文章目录 JUC组件ReentrantLock与s…

免费静态网站搭建

免费静态网站搭建 内容简介搭建步骤GitHub仓库创建Jekyll安装使用Jekyll安装指南Jekyll快速搭建测试Jekyll后续玩法 内容简介 &#x1f6a9;Tech Contents&#xff1a;GithubPage/Jekyll/Custom URLs &#x1f431;GitHub Pages&#xff1a;静态网站托管服务&#xff0c;自动将…

MySQL 8.0 OCP 1Z0-908 题目解析(21)

题目81 Choose two. Examine the modified output: mysql> SHOW SLAVE STATUS\G *************************** 1. row ***************************Slave_IO_Running: YesSlave_SQL_Running: YesSeconds_Behind_Master: 1612Seconds_Behind_Master value is steadily gro…

Web前端开发-HTML、CSS

文章目录是什么&#xff1f;HTML快速入门VS Code开发工具基础标签&样式新浪新闻-标题标题排版标题样式标题样式-1标题样式-2超链接新浪新闻-正文新浪新闻-正文排版新浪新闻-页面布局表格标签表单标签表单标签-表单项是什么&#xff1f; HTML快速入门 VS Code开发工具 基础标…

Vue.js状态管理: Vuex在大型项目中的实际应用

# Vue.js状态管理: Vuex在大型项目中的实际应用 ## 一、Vuex核心架构与大型项目适配 ### 1.1 状态管理&#xff08;State Management&#xff09;的本质需求 在复杂前端系统中&#xff0c;组件间的数据传递成本随项目规模呈指数级增长。根据Vue官方统计&#xff0c;超过500个组…

C++开发:结构体作为函数形参的值传递与引用传递

笔者定义了一个结构体变量&#xff0c;用于作为函数的形参&#xff0c;定义如下&#xff1a;struct CardParameters {float* Average nullptr;int averageSize 0; }; 需求描述&#xff1a;结构体变量作为函数的形参&#xff0c;在函数体中给指针变量分配内存空间并赋值&#…

【unity小技巧】在 Unity 中将 2D 精灵添加到 3D 游戏中,并实现阴影投射效果,实现类《八分旅人》《饥荒》等等的2.5D游戏效果

注意&#xff1a;考虑到unity小技巧的内容比较多&#xff0c;我将该内容分开&#xff0c;并全部整合放在【unity小技巧】专栏里&#xff0c;感兴趣的小伙伴可以前往逐一查看学习。 文章目录 前言实战1、在3D场景中&#xff0c;新建一些不同形状的2D图片2、我们新建一个Lit材质3…

Rust 内存结构:深入解析

Rust 的内存管理系统是其核心特性之一&#xff0c;结合了手动内存管理的效率与自动内存管理的安全性。以下是 Rust 内存结构的全面解析&#xff1a; 内存布局概览 ----------------------- | 代码段 (Text) | 只读&#xff0c;存储可执行指令 ----------------------…

【Chrome】‘Good助手‘ 扩展程序使用介绍

这是我开发的一款 Chrome 浏览器扩展程序&#xff0c;目前主要集成了‘AI对话‘&#xff0c;’总结页面’&#xff0c;‘基于页面问答’等功能&#xff0c;最近几天我也将写一篇介绍如何开发 chrome 扩展程序的博客&#xff0c;带你了解如何开发属于自己的插件。 注&#xff1…

基于mysql8.0.27部署1主2从的MHA集群

目录 一、mysql概述 1.1、关系型数据库 1.2、MySQL数据库 1.3、RDBMS术语 二、mysql的部署 2.1、拉取mysql 2.2、解压 2.3、 改名 2.4、 指定安装文件位置 2.5、 创建用户组 2.6、 修改mysql配置文件 2.7、创建data文件夹 2.8、更改mysql目录权限 2.9、初始化数据…

Highcharts 安装使用教程

一、Highcharts 简介 Highcharts 是一款使用 JavaScript 编写的前端数据可视化库&#xff0c;支持折线图、柱状图、饼图、面积图、散点图等多种图表类型&#xff0c;特点是渲染性能优秀、交互丰富、兼容性强&#xff0c;适合构建商业图表、统计报表等。 二、Highcharts 安装方…

Qt中的坐标系

Qt中的坐标系 1.坐标系概念2.数学坐标系VS计算机坐标系3.Qt坐标系4.像素 &#x1f31f;&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#x1f31f;&#x1f31f; &#x1f680;&#x1f680;系列专栏&#xff1a;【Qt的学习】 &#x1f4dd;&#x1f4dd;本篇内容&am…

C++原子类型操作与内存序

C原子类型操作与内存序详解 这段内容深入介绍了C标准原子类型的操作接口、内存序语义及使用规范。以下是关键知识点的分层解析&#xff1a; 一、原子类型的命名规则与类型映射 C提供两种方式表示原子类型&#xff1a; 模板特化形式&#xff1a;std::atomic<T>别名形式…