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…...
JavaWeb--前端--01HTML和CSS
文章目录 1 前端开发介绍2 开发工具3 文档查阅4 VSCode的插件 1 前端开发介绍 Web标准也称为网页标准,由一系列的标准组成,大部分由W3C( World Wide Web Consortium,万维网联盟)负责制定。由三个组成部分:…...
Oracle SQL中的DECODE函数与NVL函数:区别与应用场景详析
Oracle SQL中的DECODE函数与NVL函数:区别与应用场景详析 引言1. NVL函数简介与使用示例2. DECODE函数简介与使用示例3. NVL与DECODE函数的区别4. 使用场景举例结论 引言 在Oracle数据库开发和数据分析过程中,DECODE函数和NVL函数都是非常实用且常见的工具…...
算法设计与分析实验报告c++实现(N皇后问题、卫兵布置问题、求解填字游戏问题、图的m着色问题)
一.N皇后问题 基本原理和思路: 从一条路往前走,能进则进,不能进则退回来,换一条路再试。在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一…...
深入探索Linux中的libgdbus:GDBus库的应用和实现
引言 在Linux系统中,DBus是一种高效的进程间通信(IPC)机制,广泛应用于桌面环境和系统服务之间的通信。GDBus是基于GLib库的DBus实现,作为libgdbus的一部分提供。它旨在提供一种简洁、高效的方式来实现DBus通信。通过深…...
MacOS下Qt 5开发环境安装与配置
最近笔者在MacOS中使用Qt Creator开发Qt程序时遇到了一些问题,在网上查了不少资料,都没有找到解决方案,只有自己进行研究摸索了,今天晚上终于将目前遇到的问题全部解决了,特记录下来分享给大家。 笔者使用的是MacOS 1…...
jquery 实现倒计时
$(".tableText").click(function () { var time 60; var timer setInterval(function(){ time--; $(".tableText").text("("time"秒)重发"); if(time0){ clearI…...
MYSQL 5.7重置root密码
Mysql 5.7重置root密码 如果您忘记了MySQL 5.7的root密码,可以通过以下步骤重置: 停止MySQL服务。在命令行中输入以下命令: systemctl stop mysqld启动MySQL服务并跳过授权表。在命令行中输入以下命令: mysqld_safe --skip-gra…...
博客永久链接与计数
概述 工欲善其事,必先利其器。 对自己的博客不好用不满意很久了,但是这几年太懒。想趁着放假弄一下吧,发现几年没动,版本升级后很多东西变了,折腾了一下午效果不太理想。先记录一下。 问题 博客链接中有中文&#x…...
基于 RisingWave 和 ScyllaDB 构建事件驱动应用
概览 在构建事件驱动应用时,人们面临着两大挑战:1)低延迟处理大量数据;2)实现流数据的实时摄取和转换。 结合 RisingWave 的流处理功能和 ScyllaDB 的高性能 NoSQL 数据库,可为构建事件驱动应用和数据管道…...
mysql8.0高可用集群架构实战
MySQL :: MySQL Shell 8.0 :: 7 MySQL InnoDB Cluster 基本概述 InnoDB Cluster是MySQL官方实现高可用读写分离的架构方案,其中包含以下组件 MySQL Group Replication,简称MGR,是MySQL的主从同步高可用方案,包括数据同步及角色选举Mysql Shell 是InnoDB Cluster的管理工具,用…...
godaddy如何创建网站/最大免费广告发布平台
选课系统6. 创建数据库创建数据库设置编码为UTF8CREATE DATABASE choose CHARSET utf8;6.1 创建班级表表名:classes字段:class_no 整型 自增长 主键 -- 班级编号class_name char(20) 非空 唯一 -- 班级名称department_name char(20) 非空 -- 院系名称create tableclasses(cl…...
新手建站教程视频/电子商务网站
一、抽象工厂模式简介(Bref Introduction) 抽象工厂模式(Abstract Factory Pattern),提供一个创建一系列相关或者相互依赖对象的接口,而无需制定他们的具体类。优点是:易于交换产品系列…...
温州建设网站/汽油价格最新调整最新消息
一、Dubbo介绍 1、dubbo 是什么 Dubbo是一个分布式服务框架,以及SOA治理方案。其功能主要包括:高性能NIO通讯及多协议集成,服务动态寻址与路由,软负载均衡与容错,依赖分析与降级等。 Dubbo是Alibaba开源的分布式服务…...
陕西省住房和城乡建设厅网站/互联网销售包括哪些
拓扑图判环使用拓扑排序判断无向图和有向图中是否存在环的区别在于: 在判断无向图中是否存在环时,是将所有度 < 1 的结点入队; 在判断有向图中是否存在环时,是将所有入度 0 的结点入队。...
asp企业营销型网站建设/杭州网站推广平台
在url地址栏传参数如果我们直接使用汉字可能有朋友会发现接受到的是乱码了或在搜索引擎过去都变乱了,下面我们来看看正确的jsp中页面间传汉字参数转码方法。转码:a.href"./showCont.jsp?tcontent" encodeURI(encodeURI(tcontent));解码&#…...
小九自助建站/十大广告联盟
关于ubuntu进行提交本地分支到远程库出现问题: 解决方案: 执行如下命令: git remote add origin gitgithub.com:yourusername/test.git yourusername:为github注册名test:为远程库名如图所示: 应执行命令为:…...