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.rhkb.cn/news/40041.html

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

相关文章

如何用腾讯云建站做好一个多语言的建筑工程网站?海外用户访问量提升3倍!分享我的经验

作为新疆地区领先的工程建筑企业&#xff0c;我们深知在数字化浪潮中&#xff0c;一个专业、高效且具备国际视野的官方网站是企业形象与业务拓展的“门面担当”。然而&#xff0c;传统的建站流程复杂、技术门槛高、多语言适配难等问题&#xff0c;曾让我们在数字化转型中举步维…

遥控器钥匙学习---通过uds指令

1、实际报文 2、硬件配置信息 使用原gateway硬件&#xff0c;软件基于sbcm-main工程新建的一个分支。主要用于钥匙学习的指令发送。 3、后续更改 这里需要细化一下&#xff0c;为了后续方便测试 4、钥匙学习策略 可以学习2把钥匙 一次可以学习把钥匙&#xff0c;uds命令&…

QinQ项展 VLAN 空间

随着以太网技术在网络中的大量部署&#xff0c;利用 VLAN 对用户进行隔离和标识受到很大限制。因为 IEEE802.1Q 中定义的 VLAN Tag 域只有 12 个比特&#xff0c;仅能表示 4096 个 VLAN&#xff0c;无法满足城域以太网中标识大量用户的需求&#xff0c;于是 QinQ 技术应运而生。…

给Web开发者的HarmonyOS指南02-布局样式

给Web开发者的HarmonyOS指南02-布局样式 本系列教程适合鸿蒙 HarmonyOS 初学者&#xff0c;为那些熟悉用 HTML 与 CSS 语法的 Web 前端开发者准备的。 本系列教程会将 HTML/CSS 代码片段替换为等价的 HarmonyOS/ArkUI 代码。 布局基础对比 在Web开发中&#xff0c;我们使用CS…

mapbox进阶,添加鹰眼图控件

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️mapboxgl-minimap 鹰眼控件二、🍀添加…

Linux 配置时间服务器

一、同步阿里云服务器时间 服务端设置 1.检查chrony服务是否安装&#xff0c;设置chrony开机自启&#xff0c;查看chrony服务状态 [rootnode1-server ~]# rpm -q chrony # rpm -q 用于查看包是否安装 chrony-4.3-1.el9.x86_64 [rootnode1-server ~]# systemctl enable --n…

Android实践开发制作小猴子摘桃小游戏

Android实践制作小猴子摘桃小游戏 实践素材项目源文件获取&#xff1a;Android可以存在版本差异项目如果不能正确运行&#xff0c;可以使用里面的素材自己构建项目Android实践制作小猴子摘桃小游戏Android实践制作小猴子摘桃小游戏https://mp.weixin.qq.com/s/jNU_hVfj9xklsil…

数据库查询练习

1.单表查询 CREATE TABLE worker (部门号 int(11) NOT NULL,职工号 int(11) NOT NULL,工作时间 date NOT NULL,工资 float(8,2) NOT NULL,政治面貌 varchar(10) NOT NULL DEFAULT 群众,姓名 varchar(20) NOT NULL,出生日期 date NOT NULL,PRIMARY KEY (职工号) ) ENGINEInnoDB…

VGG 改进:添加ScConv空间与通道特征重构卷积

目录 1. ScConv空间与通道特征重构卷积 2. VGG+ScConv模块 3. 完整代码 Tips:融入模块后的网络经过测试,可以直接使用,设置好输入和输出的图片维度即可 1. ScConv空间与通道特征重构卷积 ScConv (Spatial and Channel reconstruction Convolution) 是一种旨在减少卷积神…

如何优化SQL查询以提高数据库性能?

你正在自助餐厅&#xff0c;所有的食物看起来都很美味。但你不是拿一个盘子&#xff0c;只取你需要的&#xff0c;而是开始从各个角落堆满食物&#xff0c;弄得一团糟&#xff0c;速度也慢了下来。结果是什么&#xff1f;你拿的东西很多并且效率低下。 这就像没有优化的SQL查询…

VS2022的第一个Qt程序——实战《加载并显示图像》

目录 一、UI设计 S1&#xff1a;双击Form Files下.ui文件&#xff0c;进入ui设计界面Qt Designer S2&#xff1a;然后拖动一个Push Button和Label控件到界面 S3&#xff1a;点击信号与槽&#xff0c;然后点击PushButton往外拉一下 S4&#xff1a;松开鼠标进入配置连接界面…

决策树算法详解:从西瓜分类到实战应用

目录 0. 引言 1. 决策树是什么&#xff1f; 1.1 生活中的决策树 1.2 专业版决策树 2. 如何构建决策树&#xff1f; 2.1 关键问题&#xff1a;选哪个特征先判断&#xff1f; 2.1.1 信息熵&#xff08;数据混乱度&#xff09; 2.1.2 信息增益&#xff08;划分后的整洁度提…

Python 标准库与数据结构

Python的标准库提供了丰富的内置数据结构和函数&#xff0c;使用这些工具能为我们提供一套强有力的工具。 需要注意的是&#xff0c;相比C与Java&#xff0c;Python的一些特点&#xff1a; Python不需要显式声明变量类型Python没有模板(Template)的概念&#xff0c;因为Pytho…

VUE3 路由配置

1.下载 VueRouter 模块 在命令行中输入 yarn add vue-router 2.导⼊相关函数 在自己创建的router/index.js 文件中 import { createRouter, createWebHashHistory } from vue-router 3.创建路由实例 在自己创建的router/index.js 文件中 const theFirstRouter ()>{return…

算法训练营第二十三天 | 贪心算法(一)

文章目录 一、贪心算法理论基础二、Leetcode 455.分发饼干二、Leetcode 376. 摆动序列三、Leetcode 53. 最大子序和 一、贪心算法理论基础 贪心算法是一种在每一步选择中都采取当前状态下的最优决策&#xff0c;从而希望最终达到全局最优解的算法设计技术。 基本思想 贪心算…

Apifox下载安装

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Apifox下载安装使用1. 下载2. 安装 &#x1…

如何区别在Spring Boot 2 和 Spring Boot 3 中使用 Knife4j:集成与配置指南

在现代的 Web 开发中&#xff0c;API 文档是不可或缺的一部分。Knife4j 是基于 Swagger 的增强工具&#xff0c;它不仅提供了更友好的 API 文档界面&#xff0c;还支持更多实用的功能&#xff0c;如离线文档导出、全局参数配置等。本文将详细介绍如何在 Spring Boot 2 和 Sprin…

超融合服务器与普通服务器的具体区别

超融合服务器与普通服务器的具体区别 超融合服务器&#xff08;Hyper-Converged Infrastructure, HCI&#xff09;与传统服务器在架构设计、功能整合、管理方式、性能表现及适用场景等方面存在显著差异。以下从多个维度进行详细对比分析&#xff1a; 一、硬件架构与资源整合 集…

(基本常识)C++中const与引用——面试常问

作者&#xff1a;求一个demo 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 内容通俗易懂&#xff0c;没有废话&#xff0c;文章最后是面试常问内容&#xff08;建议通过标题目录学习&#xff09; 废话不多…

数据库与表的操作

1. SQL 分类 SQL 根据功能分为以下几类&#xff1a; **DDL **: 定义数据库对象&#xff08;库、表、列、索引等&#xff09; 常用语句&#xff1a;CREATE, DROP, ALTER, RENAME, TRUNCATE示例&#xff1a;CREATE TABLE t_user (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHA…