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…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...

【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...

Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...

多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...