SpringSecurity——前后端分离登录认证

SpringSecurity——前后端分离登录认证的整个过程

前端:

使用Axios向后端发送请求

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登录</title><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<form>用户名:<input type="text" name="username" id="username"><br>密码:<input type="password" name="password" id="password"><br><input type="button" value="登录" onclick="login()">
</form>
</body>
<script>function login() {var username = document.getElementById("username").value;var password = document.getElementById("password").value;let formData = new FormData(); // 创建formData对象formData.append("username", username);formData.append("password", password);axios.post("http://localhost:8080/login", formData).then(function (response) {console.log(response);if (response.data.code === 200) {alert("登录成功");window.location.href = "welcome.html";} else {alert("登录失败");}}).catch(function (error){console.log(error);});}
</script></html>

 后端:

Spring Security 配置指定该 URL 作为登录处理入口。

    
@Configuration
@EnableMethodSecurity
// 配置spring的容器
public class SecurityConfig {@Bean// 安全过滤器链Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity ,CorsConfigurationSource configurationSource ) throws Exception { //httpSecurity方法参数注入Beanreturn httpSecurity// 配置自己的登录页面.formLogin( (formLogin) ->{formLogin.loginProcessingUrl("/login") // 登录账户密码往哪个地址提交}) .build();}
}

由于现在是前后端分离的,所以拿不到CSRF,因此我们需要先禁用CSRF:

禁用 CSRF:

在基于 Token 的认证中,由于不依赖 Session,因此通常会关闭 CSRF 保护。可以在 HttpSecurity 中调用 .csrf().disable() 来实现这一点。

    
@Configuration
@EnableMethodSecurity
// 配置spring的容器
public class SecurityConfig {@Bean// 安全过滤器链Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity ,CorsConfigurationSource configurationSource ) throws Exception { //httpSecurity方法参数注入Beanreturn httpSecurity// 配置自己的登录页面.formLogin( (formLogin) ->{formLogin.loginProcessingUrl("/login") // 登录账户密码往哪个地址提交}) .csrf((csrf)->{// 禁止csrf跨站请求,禁用之后,肯定就不安全了,有csrf网络攻击的风险,后续加入jwt是可以防御的csrf.disable();}).build();}
}

配置 formLogin.loginProcessingUrl("/login") 实际上告诉 Spring Security:

  • 当收到指向 /login 的 POST 请求时,Spring Security 内部的过滤器(例如 UsernamePasswordAuthenticationFilter)会拦截这个请求,并自动处理用户的认证逻辑。
  • 你不需要在自己的 Controller 中实现这个 /login 接口,因为 Spring Security 会接管并执行用户名、密码的验证,以及后续的成功或失败处理(如果你配置了相应的 successHandlerfailureHandler)。

存在跨域问题:

协议不同会跨域  https://localhost:8080    http://localhost:8080

  1. 端口不同会跨域:http://localhost:10492    http://localhost:8080 
  2. 域名不同会跨域:http://bjpowernode.com   http://baidu.com 

三个里面有任何一个不同,都是跨域,跨域是浏览器不允许的,浏览器是为了安全,不允许你跨域访问

跨域资源共享(CORS)配置

  • 允许跨域访问:
    前后端分离架构中,前端通常与后端不在同一个域名下,因此必须在后端配置 CORS 策略。可以通过在 HttpSecurity 配置中调用 .cors() 方法通常需要自己定义一个 CorsConfigurationSource Bean。在自己定义 CorsConfigurationSource Bean当中我们需要返回CorsConfigurationSource(接口)的实现类——通常情况下是UrlBasedCorsConfigurationSource

@Configuration
@EnableMethodSecurity
// 配置spring的容器
public class SecurityConfig {/*** 配置跨域* @return*/@Beanpublic CorsConfigurationSource configurationSource() {UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();// 跨域配置CorsConfiguration corsConfiguration = new CorsConfiguration();corsConfiguration.setAllowedOrigins(Arrays.asList("*")); // 允许的请求来源corsConfiguration.setAllowedMethods(Arrays.asList("*")); // 允许的请求方法corsConfiguration.setAllowedHeaders(Arrays.asList("*"));// 允许的请求头// 注册配置urlBasedCorsConfigurationSource.registerCorsConfiguration("/**",corsConfiguration);return urlBasedCorsConfigurationSource;}@Bean// 安全过滤器链Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity ,CorsConfigurationSource configurationSource ) throws Exception { //httpSecurity方法参数注入Beanreturn httpSecurity// 配置自己的登录页面.formLogin( (formLogin) ->{formLogin.loginProcessingUrl("/login") // 登录账户密码往哪个地址提交}) .csrf((csrf)->{// 禁止csrf跨站请求,禁用之后,肯定就不安全了,有csrf网络攻击的风险,后续加入jwt是可以防御的csrf.disable();}).cors((cors)->{ // 允许前端跨域访问cors.configurationSource( configurationSource);}).build();}
}

凭证接收和验证: Spring Security框架使用 UsernamePasswordAuthenticationFilter 拦截请求,获取用户提交的账号和密码。

用户信息查询:

UserServiceImpl重写loadUserByUsername方法 从数据库中加载用户信息,返回一个包含用户状态和权限信息的 UserDetails(在本例中为 TUser 对象)。

重写loadUserByUsername方法需要service接口,需要继承springsecurity框架的UserDetailsService接口

// 我们的处理登录的service接口,需要继承springsecurity框架的UserDetailsService接口
public interface UserService extends UserDetailsService {
}

service实现类 

    @Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {// 通过用户名查询数据库TUser user =  userMapper.selectByLoginAct(username);if (user == null){throw new UsernameNotFoundException("用户不存在");}return user; // 实现了UserDetails接口,包含所有字段}

状态检查和密码比对: 框架会检查用户对象的状态(例如账户是否有效)以及比对密码是否匹配。

登录成功或失败的处理(处理器):

根据认证结果决定登录成功后的跳转(默认跳转到上一次请求的地址或项目根路径)或失败后的处理(重定向到 /login?error),但在前后端分离场景中,需要通过自定义 Handler 返回 JSON 格式的响应。

@Configuration
@EnableMethodSecurity
// 配置spring的容器
public class SecurityConfig {@Bean// 安全过滤器链Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity ,CorsConfigurationSource configurationSource ) throws Exception { //httpSecurity方法参数注入Beanreturn httpSecurity// 配置自己的登录页面.formLogin( (formLogin) ->{formLogin.loginProcessingUrl("/login") // 登录账户密码往哪个地址提交.successHandler(myAuthenticationSuccessHandler).failureHandler(myAuthenticationFailHandler); // 登录失败的回调}) .build();}
}
 MyAuthenticationSuccessHandle(登录成功的处理器):
@Component
public class MyAuthenticationSuccessHandle implements AuthenticationSuccessHandler {@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {R result = R.builder().code(200).msg("登录成功").info(authentication.getPrincipal()).build();response.setContentType("application/json;charset=utf-8");String json = JSONUtil.toJsonStr(result);response.getWriter().write(json);}
}
 MyAuthenticationFailHandle(登录失败的处理器):
@Component
public class MyAuthenticationFailHandle implements AuthenticationFailureHandler {@Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {R result = R.builder().code(500).msg("登录失败").info(exception.getMessage()).build();response.setContentType("application/json;charset=utf-8");String json = JSONUtil.toJsonStr(result);response.getWriter().write(json);}
}
退出成功的处理器
@Component
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {@Overridepublic void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {R result = R.builder().code(200).msg("退出成功").info(authentication.getPrincipal()).build();response.setContentType("application/json;charset=utf-8");String json = JSONUtil.toJsonStr(result);response.getWriter().write(json);}
}

在 Spring Security 中,退出操作(logout)的设计逻辑与登录有所不同。登录过程涉及用户凭证验证、状态检查和密码匹配等环节,这些都有可能失败,所以需要提供失败处理器(如登录失败处理器)。而退出操作本质上只是清理会话、清空 SecurityContext 等动作,通常不会出现“失败”的情况。因此,框架只提供了退出成功处理器(LogoutSuccessHandler),而没有专门的退出失败处理器。

无状态认证的考虑:

由于不再使用传统 Session 记录用户状态,后续访问其他需要认证的接口时会提示未登录,此时通常会引入 JWT 等机制来维持用户认证状态。

没有session、前端cookie中也不会存储sessionid;那么这样的话,用户状态怎么保持呢?

需要使用我们下面介绍的jwt解决该问题;

不分离的:Tomcat 【thymeleaf  <----> (controller、sucurity)】

前后端分离:Nginx 【Vue】  <----jwt---->  Tomcat 【 (controller、sucurity) 】

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

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

相关文章

qt下载和安装教程国内源下载地址

qt不断在更新中&#xff0c;目前qt6日渐成熟&#xff0c;先前我们到官方下载或者国内镜像直接可以下载到exe文件安装&#xff0c;但是最近几年qt官方似乎在逐渐关闭旧版本下载通道&#xff0c;列为不推荐下载。但是qt5以其广泛使用和稳定性&#xff0c;以及积累大量代码使得qt5…

Mysql架构理论部分

Mysql架构是什么&#xff1f;实际可以理解为执行一条sql语句所要经历的阶段有哪些&#xff01; 1.连接层 &#xff08;1&#xff09;客户端发起连接 客户端通过TCP/IP、Unix Socket或命名管道等方式向Mysql服务器发起链接请求 想要了解tcp与udp的区别&#xff0c;可以参考这…

架构师面试(十九):IM 架构

问题 IM 系统从架构模式上包括 【介绍人模式】和 【代理人模式】。介绍人模式也叫直连模式&#xff0c;消息收发不需要服务端的参与&#xff0c;即客户端之间直连的方式&#xff1b;代理人模式也叫中转模式&#xff0c;消息收发需要服务端进行中转。 下面关于这两类模式描述的…

【服务器】RAID0、RAID1、RAID5、RAID6、RAID10异同与应用

目录 ​编辑 一、RAID概述 1.1 磁盘阵列简介 1.2 功能 二、RAID级别 2.1 RAID 0&#xff08;不含校验与冗余的条带存储&#xff09; 2.2 RAID1&#xff08;不含校验的镜像存储&#xff09; 2.3 RAID 5 &#xff08;数据块级别的分布式校验条带存储&#xff09; 4、RAI…

MySQL身份验证的auth_socket插件

在Ubuntu 20.04 LTS上&#xff0c;MySQL 8.0默认使用auth_socket插件进行身份验证&#xff0c;可能存在意想不到的情况。 一、auth_socket插件 在使用sudo mysql或通过sudo切换用户后执行任何MySQL命令时&#xff0c;不需要输入密码或错误密码都可以正常登入mysql数据库&…

小程序开发中的用户反馈收集与分析

我们在开发小程序的过程中根据开发过程中的代码及业务场景,以下是针对需求管理系统的用户反馈收集与分析方案设计: 需求管理系统用户反馈收集与分析方案 一、反馈数据模型设计 // 新增Feedback模型(app/admin/model/Feedback.php) namespace app\admin\model; use think\…

python关键字汇总

文章目录 1. 变量与类型相关2. 控制流相关3. 函数与类相关4. 异常处理相关5. 模块相关6. 其他 在 Python 3 里有 35 个关键字&#xff0c;它们各自具备特定的用途与意义 1. 变量与类型相关 True、False 意义&#xff1a;布尔类型的常量&#xff0c;分别代表逻辑真与逻辑假。示…

使用Python在Word中创建、读取和删除列表 - 详解

目录 工具与设置 Python在Word中创建列表 使用默认样式创建有序&#xff08;编号&#xff09;列表 使用默认样式创建无序&#xff08;项目符号&#xff09;列表 创建多级列表 使用自定义样式创建列表 Python读取Word中的列表 Python从Word中删除列表 在Word中&#xff…

软考-软件设计师-计算机网络

一、七层模型 中继器&#xff1a;信号会随着距离的增加而逐渐衰减&#xff0c;中继器可以接受一端的信息再将其原封不动的发给另一端&#xff0c;起到延长传输距离的作用&#xff1b; 集线器&#xff1a;多端口的中继器&#xff0c;所有端口公用一个冲突域&#xff1b; 网桥&…

关于Flask框架30道面试题及解析

文章目录 基础概念1. 什么是Flask?其核心特性是什么?2. Flask和Django的主要区别?3. 解释Flask中的“路由”概念。如何定义动态路由?核心组件4. Flask的请求上下文(Request Context)和应用上下文(Application Context)有什么区别?5. 如何访问请求参数?POST和GET方法的…

C++20 中 `constexpr` 的强大扩展:算法、工具与复数库的变革

文章目录 一、constexpr 在 <algorithm> 中的应用1. 编译时排序2. 编译时查找 二、constexpr 在 <utility> 中的应用1. 编译时交换2. 编译时条件交换 三、constexpr 在 <complex> 中的应用1. 编译时复数运算 四、总结 C20 对 constexpr 的增强是其最引人注目…

【ELK】节省存储 之 压缩存储方式调整

目录 集群版本&#xff1a; 7.17.6 解释几个概念&#xff1a; 段&#xff08;Segment&#xff09; 合并(Merge) 索引设置&#xff1a; 压缩方式(index.codec)&#xff1a; 测试设置前提条件 对比 在创建的时候指定压缩类型&#xff08;index.codec&#xff09; 对比 在…

conda create之后,以前的conda env list 只能看到环境路径 没有环境名称了

1.命令 conda env list 看到的显示如下&#xff1a; 左边这列的"base"&#xff0c;指向的路径和其它环境变量安装的路径不一致。 这时需要通过"activate [anaconda的环境路径]"和"source activate"回到anaconda&#xff1a; 2.执行切换命令 …

夸克网盘任务脚本——进阶自动版

脚本是用于自动管理和更新夸克云盘(Quark Cloud Drive)上的文件和目录的Python脚本。其主要功能包括自动下载、更新、重命名、删除文件和文件夹,以及处理和发送通知,可以在特定的时间间隔内运行,根据配置文件进行操作。 主要功能 1. Quark 类: __init__:初始化类,设置…

AsyncHttpClient使用说明书

[[toc]] AsyncHttpClient(AHC)是一个高性能、异步的 HTTP 客户端库,广泛用于 Java 和 Scala 应用中,特别适合处理高并发、非阻塞的 HTTP 请求。它基于 Netty 或 Java 原生的异步 HTTP 客户端实现,支持 HTTP/1.1 和 HTTP/2 协议,适用于微服务、API 调用、爬虫等场景。 1.…

Powershell、Windows Shell、CMD 的区别与联系

Powershell、Windows Shell、CMD 的区别与联系 一、核心概念 名称 全称 类型 发布时间 CMD Command Prompt 命令行解释器&#xff08;CLI&#xff09; 1985&#xff08;DOS&#xff09; Powershell Windows PowerShell 任务自动化脚本环境 2006 Windows Shell Wi…

vulnhub-Tr0ll ssh爆破、wireshark流量分析,exp、寻找flag。思维导图带你清晰拿到所以flag

vulnhub-Tr0ll ssh爆破、wireshark流量分析&#xff0c;exp、寻找flag。思维导图带你清晰拿到所以flag 1、主机发现 arp-scan -l 2、端口扫描 nmap -sS -sV 192.168.66.185 nmap -sS -A -T4 -p- 192.168.66.185 nmap --scriptvuln 192.168.66.185经典扫描三件套&#xff0c;…

强化学习(赵世钰版)-学习笔记(8.值函数方法)

本章是算法与方法的第四章&#xff0c;是TD算法的拓展&#xff0c;本质上是将状态值与行为值的表征方式&#xff0c;从离散的表格形式&#xff0c;拓展到了连续的函数形式。 表格形式的优点是直观&#xff0c;便于分析&#xff0c;缺点是数据量较大或者连续性状态或者行为空间时…

[特殊字符] 2025蓝桥杯备赛Day7——B2117 整理药名

&#x1f50d; 2025蓝桥杯备赛Day7——B2117 整理药名 题目难度&#xff1a;⭐️ 适合掌握字符串基础操作 考察重点&#xff1a;大小写转换、字符串遍历、边界条件处理 B2117 整理药名 题目描述 医生在书写药品名的时候经常不注意大小写&#xff0c;格式比较混乱。现要求你…

笛卡尔轨迹规划之齐次变换矩阵与欧拉角、四元数的转化

一、笛卡尔轨迹规划需求 笛卡尔轨迹规划本质就是我们对机械臂的末端位置和姿态进行规划&#xff0c;其实也就是对末端坐标系的位姿进行规划。我们清楚末端坐标系的位姿是可以用齐次变换矩阵T来表示的&#xff0c;但这样表示的话&#xff0c;并不利于我们去做规划&#xff0c;所…