SpringBoot3配置SpringSecurity6
访问1:localhost:8080/security,返回:需要先认证才能访问(说明没有权限)
访问2:localhost:8080/anonymous,返回:anonymous(说明正常访问)
相关文件如下:
pom.xml:
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.4</version><relativePath/> <!-- lookup parent from repository --></parent><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.18</version></dependency>
WebSecurityConfiguration:
/*** Spring Security 配置项*/
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@EnableGlobalAuthentication
public class WebSecurityConfiguration {@Autowiredprivate JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;@Autowiredprivate RestAuthenticationEntryPoint restAuthenticationEntryPoint;@Autowiredprivate RestAccessDeniedHandler restAccessDeniedHandler;private UserDetailsService userDetailsService;@Autowiredprivate ApplicationContext applicationContext;@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {// 搜寻 匿名标记 url: PreAuthorize("hasAnyRole('anonymous')") 和 PreAuthorize("@tsp.check('anonymous')") 和 AnonymousAccessMap<RequestMappingInfo, HandlerMethod> handlerMethodMap = applicationContext.getBean(RequestMappingHandlerMapping.class).getHandlerMethods();Set<String> anonymousUrls = new HashSet<>();for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) {HandlerMethod handlerMethod = infoEntry.getValue();AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);PreAuthorize preAuthorize = handlerMethod.getMethodAnnotation(PreAuthorize.class);PathPatternsRequestCondition pathPatternsCondition = infoEntry.getKey().getPathPatternsCondition();Set<String> patternList = new HashSet<>();if (null != pathPatternsCondition){Set<PathPattern> patterns = pathPatternsCondition.getPatterns();for (PathPattern pattern : patterns) {patternList.add(pattern.getPatternString());}}if (null != preAuthorize && preAuthorize.value().toLowerCase().contains("anonymous")) {anonymousUrls.addAll(patternList);} else if (null != anonymousAccess && null == preAuthorize) {anonymousUrls.addAll(patternList);}}httpSecurity// 禁用basic明文验证.httpBasic(it -> it.disable())// 前后端分离架构不需要csrf保护.csrf(it -> it.disable())// 禁用默认登录页.formLogin(it -> it.disable())// 禁用默认登出页.logout(it -> it.disable())// 设置异常的EntryPoint,如果不设置,默认使用Http403ForbiddenEntryPoint.exceptionHandling(exceptions -> {// 401exceptions.authenticationEntryPoint(restAuthenticationEntryPoint);// 403exceptions.accessDeniedHandler(restAccessDeniedHandler);})// 前后端分离是无状态的,不需要session了,直接禁用。.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)).authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests// 允许匿名访问.requestMatchers(anonymousUrls.toArray(new String[0])).permitAll()// 允许所有OPTIONS请求.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()// 允许 SpringMVC 的默认错误地址匿名访问.requestMatchers("/error").permitAll()// 允许任意请求被已登录用户访问,不检查Authority.anyRequest().authenticated()).authenticationProvider(authenticationProvider())// 加我们自定义的过滤器,替代UsernamePasswordAuthenticationFilter.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);return httpSecurity.build();}@Beanpublic CorsFilter corsFilter() {UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();CorsConfiguration config = new CorsConfiguration();// 允许所有域名进行跨域调用config.addAllowedOrigin("*");// 放行全部原始头信息config.addAllowedHeader("*");// 允许所有请求方法跨域调用config.addAllowedMethod("OPTIONS");config.addAllowedMethod("GET");config.addAllowedMethod("POST");config.addAllowedMethod("PUT");config.addAllowedMethod("DELETE");source.registerCorsConfiguration("/**", config);return new CorsFilter(source);}@Beanpublic UserDetailsService userDetailsService() {return username -> userDetailsService.loadUserByUsername(username);}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Beanpublic AuthenticationProvider authenticationProvider() {DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();authProvider.setUserDetailsService(userDetailsService());// 设置密码编辑器authProvider.setPasswordEncoder(passwordEncoder());return authProvider;}}
JwtAuthenticationTokenFilter
/*** JWT登录授权过滤器*/@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response,@NonNull FilterChain chain) throws ServletException, IOException {String authorization = request.getHeader("Authorization");response.setCharacterEncoding("utf-8");if (null == authorization){// 没有tokenchain.doFilter(request, response);return;}try{if (!authorization.startsWith("Bearer ")){// token格式不正确response.sendError(HttpServletResponse.SC_BAD_REQUEST, "token格式不正确");return;}boolean verify = MyJWTUtil.verify(authorization);if(!verify){// token格式不正确response.sendError(HttpServletResponse.SC_BAD_REQUEST, "token验证失败");return;}}catch (Exception e){// token格式不正确response.sendError(HttpServletResponse.SC_BAD_REQUEST, "token验证失败");return;}JWT jwt = MyJWTUtil.parseToken(authorization);Object uid = jwt.getPayload("uid");// todo 解析JWT获取用户信息LoginUser loginUser = new LoginUser();UsernamePasswordAuthenticationToken authenticationToken =new UsernamePasswordAuthenticationToken(loginUser,null,null);SecurityContextHolder.getContext().setAuthentication(authenticationToken);chain.doFilter(request, response);}}
RestAuthenticationEntryPoint:
/*** 认证失败处理类*/@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response,AuthenticationException authException) throws IOException {response.setHeader("Access-Control-Allow-Origin", "*");response.setHeader("Cache-Control", "no-cache");response.setContentType("application/json");response.setCharacterEncoding("UTF-8");response.setStatus(HttpStatus.UNAUTHORIZED.value());response.getWriter().println(authException == null? "Unauthorized" : "需要先认证才能访问");response.getWriter().flush();}}
RestAccessDeniedHandler:
/*** 自定义无权访问处理类*/
@Component
public class RestAccessDeniedHandler implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response,AccessDeniedException accessDeniedException) throws IOException {response.setHeader("Access-Control-Allow-Origin", "*");response.setHeader("Cache-Control", "no-cache");response.setContentType("application/json");response.setCharacterEncoding("UTF-8");response.setStatus(HttpStatus.FORBIDDEN.value());
// response.getWriter()
// .println(accessDeniedException==null?"AccessDenied":accessDeniedException.getMessage());response.getWriter().println(accessDeniedException == null? "AccessDenied" : "没有访问权限");response.getWriter().flush();}}
AnonymousAccess:
/*** 用于标记匿名访问方法*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnonymousAccess {}
MyJWTUtil:
/*** JWT工具类*/
public class MyJWTUtil extends JWTUtil {/*** 解析JWT Token** @param token token* @return {@link JWT}*/public static boolean verify(String token) {return verify(token, "LOGIN_TOKEN_KEY_20240410".getBytes());}/*** 解析JWT Token** @param token token* @return {@link JWT}*/public static boolean verify(String token, byte[] key) {if(StrUtil.isNotEmpty(token)){if(token.startsWith("Bearer ")){token = token.split("Bearer ")[1].trim();}}return JWT.of(token).setKey(key).verify();}/*** 解析JWT Token** @param token token* @return {@link JWT}*/public static JWT parseToken(String token) {if(StrUtil.isNotEmpty(token)){if(token.startsWith("Bearer ")){token = token.split("Bearer ")[1].trim();}}return JWT.of(token);}public static String getToken(HttpServletRequest request) {final String requestHeader = request.getHeader("Authorization");if (requestHeader != null && requestHeader.startsWith("Bearer ")) {return requestHeader.substring(7);}return null;}public static String createToken(String userId) {Map<String, Object> payload = new HashMap<>(4);payload.put("uid", userId);payload.put("expire_time", System.currentTimeMillis() + 1000 * 60 * 60 * 8);return createToken(payload, "LOGIN_TOKEN_KEY_20240410".getBytes());}
}
DemoController:
@RestController
public class DemoController {@GetMapping("anonymous")@AnonymousAccesspublic String loadCondition() {return "anonymous";}@GetMapping("security")public String security() {return "security";}}
相关文章:
SpringBoot3配置SpringSecurity6
访问1:localhost:8080/security,返回:需要先认证才能访问(说明没有权限) 访问2:localhost:8080/anonymous,返回:anonymous(说明正常访问) 相关文件如下&…...
Unity之Unity面试题(三)
内容将会持续更新,有错误的地方欢迎指正,谢谢! Unity之Unity面试题(三) TechX 坚持将创新的科技带给世界! 拥有更好的学习体验 —— 不断努力,不断进步,不断探索 TechX —— 心探索、心进取…...
Linux命令-dos2unix命令(将DOS格式文本文件转换成Unix格式)
说明 dos2unix命令 用来将DOS格式的文本文件转换成UNIX格式的(DOS/MAC to UNIX text file format converter)。DOS下的文本文件是以 \r\n 作为断行标志的,表示成十六进制就是0D0A。而Unix下的文本文件是以\n作为断行标志的,表示成…...
企业怎么做数据分析
数据分析在当今信息化时代扮演着至关重要的角色。能够准确地收集、分析和利用数据,对企业的决策和发展都具有重要意义。数聚将介绍企业如何合理地利用数据分析,如何协助企业在竞争激烈的市场中取得优势。 一、建立完善的数据收集系统 在进行数据分析之…...
1111111111
c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话: 知不足而奋进,望远山而前行&am…...
[面向对象] 单例模式与工厂模式
单例模式 是一种创建模式,保证一个类只有一个实例,且提供访问实例的全局节点。 工厂模式 面向对象其中的三大原则: 单一职责:一个类只有一个职责(Game类负责什么时候创建英雄机,而不需要知道创建英雄机要…...
《前端防坑》- JS基础 - 你觉得typeof nullValue === null 么?
问题 JS原始类型有6种Undefined, Null, Number, String, Boolean, Symbol共6种。 在对原始类型使用typeof进行判断时, typeof stringValue string typeof numberValue number 如果一个变量(nullValue)的值为null,那么typeof nullValue "?" const u …...
【项目实战经验】DataKit迁移MySQL到openGauss(下)
上一篇我们分享了安装、设置、链接、启动等步骤,本篇我们将继续分享迁移、启动~ 目录 9. 离线迁移 9.1. 迁移插件安装 中断安装,比如 kill 掉java进程(安装失败也要等待300s) 下载安装包准备上传 缺少mysqlclient lib包 mysq…...
AI预测体彩排3第2弹【2024年4月13日预测--第1套算法开始计算第2次测试】
各位小伙伴,今天实在抱歉,周末回了趟老家,回来比较晚了,数据今天上午跑完后就回老家了,晚上8点多才回来,赶紧把预测结果发出来吧,虽然有点晚了,但是咱们前面说过了,目前的…...
【13137】质量管理(一)2024年4月串讲题组一
目录 1.选择题 2.多选题 3.简答题 4.论述题 5.计算题 6.论述题 【13137】质量管理-速 记 宝 典【全国通用】</...
Go语言中工作负载类型对并发的影响
在实际工作开发中我们需要根据工作负载是CPU密集型还是I/O密集型,使用不同的方式来解决问题。下面我们先来看这些概念,然后再讨论其影响。 在程序执行时,工作负载的执行时间会受以下因素限制: CPU的速度--例如,运行归并排序算法。工作负载被称为CPU密集型。I/O速度--例如…...
常用的Python内置函数
目录 1. getattr() 函数: 2. setattr() 函数: 3. id():返回对象的唯一标识符(内存地址)。 4. type():返回对象的类型。 5. isinstance(obj, classinfo):判断对象是否是某种类型或其子类的实例。 6. issubclass(class1, class2):判断一个类是否是另一个类的子类。 …...
MAC(M1芯片)编译Java项目慢且发热严重问题解决方案
目录 一、背景二、排查三、解决四、效果以及结果展示五、总结 一、背景 使用idea编译项目等操作,经常性发热严重,并且时间慢。直到昨天编译一个项目用时30分钟,电脑温度很高,并且有烧灼的味道,于是有了此篇文章。 二、…...
如何循环pandas格式的数据
如何循环pandas格式的数据 要循环处理 Pandas 格式的数据,可以使用 iterrows() 方法或者 iteritems() 方法。 iterrows() 方法: import pandas as pd# 假设 df 是你的 Pandas DataFrame for index, row in df.iterrows():# 在这里处理每一行的数据&am…...
新零售SaaS架构:客户管理系统架构设计(万字图文总结)
什么是客户管理系统? 客户管理系统,也称为CRM(Customer Relationship Management),主要目标是建立、发展和维护好客户关系。 CRM系统围绕客户全生命周期的管理,吸引和留存客户,实现缩短销售周…...
Apache Spark
Apache Spark是一种开源的分布式计算系统,主要用于大数据处理和分析。Spark提供了一个高效的计算引擎,可以在分布式环境中处理大规模数据集。它支持多种编程语言,包括Scala、Java、Python和R。 Spark的核心概念是弹性分布式数据集࿰…...
CentOS7编译ZLMediaKit并使能WebRTC
使能WebRTC需要libsrtp库, libsrtp库需要openssl, 所以第一步先安装openssl, 系统自带的版本是1.0.2的, libsrtp需要1.1.1以上版本, 需要使用源码进行编译; GCC准备 需要安装gcc7以上版本, 并切换到gcc7的编译环境 yum install centos-release-scl yum install devtoolset-7…...
【数据交换格式】网络socket编程温度采集智能存储与上报项目技术------JSON、TLV
作者简介: 一个平凡而乐于分享的小比特,中南民族大学通信工程专业研究生在读,研究方向无线联邦学习 擅长领域:驱动开发,嵌入式软件开发,BSP开发 作者主页:一个平凡而乐于分享的小比特的个人主页…...
IP地址定位技术在各领域的作用
IP地址定位是通过确定IP地址的物理位置来定位一个设备的技术,它在现代社会的多个领域中都有着广泛的应用。以下将详细探讨IP地址定位的应用场景,以期对读者有所启发。 首先,在网络安全领域,IP地址定位发挥着至关重要的作用。网络…...
代码随想录 538. 把二叉搜索树转换为累加树
题目 给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。 提醒一下,二叉搜索树满足下列约束条件&a…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
MySQL 部分重点知识篇
一、数据库对象 1. 主键 定义 :主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 :确保数据的完整性,便于数据的查询和管理。 示例 :在学生信息表中,学号可以作为主键ÿ…...
Windows 下端口占用排查与释放全攻略
Windows 下端口占用排查与释放全攻略 在开发和运维过程中,经常会遇到端口被占用的问题(如 8080、3306 等常用端口)。本文将详细介绍如何通过命令行和图形化界面快速定位并释放被占用的端口,帮助你高效解决此类问题。 一、准…...
