RuoYi若依源码分析1 - security

Security

springsecurity配置文件夹 security
image.png
springsecurity总配置类 SecurityConfig.java
image.png

SecurityConfig

总配置分析

首先看一下总配置,我们可以从总配置项里面大体的总结出springsecurity鉴权在ruoyi框架里面是如何执行的

  1. 自动装配关键处理类以及过滤器等工具类
  2. @EnableGlobalMethodSecurity表示启用了Spring Security的方法级安全性(Method Security),允许在方法级别进行安全控制
  3. 继承WebSecurityConfigurerAdapter,这是Spring Security提供的用于自定义安全配置的基类
  4. configure(HttpSecurity httpSecurity)配置HTTP请求的方法,它定义了哪些请求需要进行身份认证和授权
  5. configure(AuthenticationManagerBuilder auth)配置用户身份认证的方法

其中配置HTTP请求的方法configure主要需要实现一下功能

  • 禁用CSRF
  • 禁用session,因为我们采用的是token校验方式
  • 认证失败的处理方法
  • 静态资源、登录界面等设置不拦截
  • 其余敏感界面设置拦截
  • 依次设置三大过滤器:logout、JWT、CORS
总配置代码
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
{/*** 自定义用户认证逻辑*/@Autowiredprivate UserDetailsService userDetailsService;/*** 认证失败处理类*/@Autowiredprivate AuthenticationEntryPointImpl unauthorizedHandler;/*** 退出处理类*/@Autowiredprivate LogoutSuccessHandlerImpl logoutSuccessHandler;/*** token认证过滤器*/@Autowiredprivate JwtAuthenticationTokenFilter authenticationTokenFilter;/*** 跨域过滤器*/@Autowiredprivate CorsFilter corsFilter;/*** 允许匿名访问的地址*/@Autowiredprivate PermitAllUrlProperties permitAllUrl;/*** 解决 无法直接注入 AuthenticationManager** @return* @throws Exception*/@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception{return super.authenticationManagerBean();}/*** anyRequest          |   匹配所有请求路径* access              |   SpringEl表达式结果为true时可以访问* anonymous           |   匿名可以访问* denyAll             |   用户不能访问* fullyAuthenticated  |   用户完全认证可以访问(非remember-me下自动登录)* hasAnyAuthority     |   如果有参数,参数表示权限,则其中任何一个权限可以访问* hasAnyRole          |   如果有参数,参数表示角色,则其中任何一个角色可以访问* hasAuthority        |   如果有参数,参数表示权限,则其权限可以访问* hasIpAddress        |   如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问* hasRole             |   如果有参数,参数表示角色,则其角色可以访问* permitAll           |   用户可以任意访问* rememberMe          |   允许通过remember-me登录的用户访问* authenticated       |   用户登录后可访问*/@Overrideprotected void configure(HttpSecurity httpSecurity) throws Exception{// 注解标记允许匿名访问的urlExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity.authorizeRequests();permitAllUrl.getUrls().forEach(url -> registry.antMatchers(url).permitAll());httpSecurity// CSRF禁用,因为不使用session.csrf().disable()// 禁用HTTP响应标头.headers().cacheControl().disable().and()// 认证失败处理类.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()// 基于token,所以不需要session.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()// 过滤请求.authorizeRequests()// 对于登录login 注册register 验证码captchaImage 允许匿名访问.antMatchers("/login", "/register", "/captchaImage").permitAll()// 静态资源,可匿名访问.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll().antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()// 除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated().and().headers().frameOptions().disable();// 添加Logout filterhttpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);// 添加JWT filterhttpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);// 添加CORS filterhttpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class);httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class);}/*** 强散列哈希加密实现*/@Beanpublic BCryptPasswordEncoder bCryptPasswordEncoder(){return new BCryptPasswordEncoder();}/*** 身份认证接口*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception{auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());}
}

security主要实现类

AuthenticationContextHolder

这段代码定义了一个名为 AuthenticationContextHolder 的类,它提供了一种在应用程序中管理用户身份认证上下文的方式。
身份认证上下文通常用于在应用程序中存储和管理当前用户的身份认证信息,以便在处理请求时进行身份验证和授权。以下是这个类的主要功能和意义:

  1. contextHolder 静态变量:
  • 这是一个 ThreadLocal 类型的静态变量,它用于在每个线程中存储 Authentication 对象。Authentication 通常代表了用户的身份认证信息,例如用户名、密码、角色等。
  1. getContext 方法:
  • 这个方法用于获取当前线程的身份认证上下文。
  • 它通过 contextHolder.get() 方法从当前线程的 ThreadLocal 存储中检索 Authentication 对象,并返回它。
  1. setContext 方法:
  • 这个方法用于设置当前线程的身份认证上下文。
  • 它通过 contextHolder.set(context) 将传入的 Authentication 对象存储到当前线程的 ThreadLocal 存储中。
  1. clearContext 方法:
  • 这个方法用于清除当前线程的身份认证上下文。
  • 通过 contextHolder.remove() 方法从当前线程的 ThreadLocal 存储中删除存储的 Authentication 对象。
public class AuthenticationContextHolder
{private static final ThreadLocal<Authentication> contextHolder = new ThreadLocal<>();public static Authentication getContext(){return contextHolder.get();}public static void setContext(Authentication context){contextHolder.set(context);}public static void clearContext(){contextHolder.remove();}
}
PermissionContextHolder

这段代码定义了一个名为 PermissionContextHolder 的类,它提供了一种在应用程序中存储和获取权限上下文的方式。权限上下文通常用于标识当前用户或会话的访问权限,以便在应用程序的不同部分中轻松地检查和控制访问权限。以下是这个类的主要功能和意义:

  1. setContext 方法:
  • 这个方法用于将权限信息(通常是一个字符串或权限标识)设置到当前请求的上下文中。
  • 它通过 RequestContextHolder.currentRequestAttributes() 获取当前请求的属性,然后使用 setAttribute 方法将权限信息存储在 PERMISSION_CONTEXT_ATTRIBUTES 键下。
  • 存储权限信息时,指定了 RequestAttributes.SCOPE_REQUEST,表示权限信息将与当前请求的生命周期相关联。
  1. getContext 方法:
  • 这个方法用于获取当前请求的权限上下文信息。
  • 它通过 RequestContextHolder.currentRequestAttributes() 获取当前请求的属性,然后使用 getAttribute 方法从上下文中检索存储的权限信息。
  • 最后,它返回存储的权限信息,通常是一个字符串。
public class PermissionContextHolder
{private static final String PERMISSION_CONTEXT_ATTRIBUTES = "PERMISSION_CONTEXT";public static void setContext(String permission){RequestContextHolder.currentRequestAttributes().setAttribute(PERMISSION_CONTEXT_ATTRIBUTES, permission,RequestAttributes.SCOPE_REQUEST);}public static String getContext(){return Convert.toStr(RequestContextHolder.currentRequestAttributes().getAttribute(PERMISSION_CONTEXT_ATTRIBUTES,RequestAttributes.SCOPE_REQUEST));}
}
JwtAuthenticationTokenFilter

这段代码定义了一个名为 JwtAuthenticationTokenFilter 的类,它是一个Spring框架中的过滤器(Filter),通常用于在处理HTTP请求时进行身份验证和授权。这个过滤器主要用于处理JSON Web Token(JWT)身份认证,并在请求中验证和设置用户的认证信息。以下是这个类的主要功能和意义:

  1. 这个过滤器扩展了 OncePerRequestFilter,这是Spring框架提供的过滤器抽象类,它确保每个HTTP请求只会被过滤一次。
  2. @Autowired 注解用于注入一个名为 tokenService 的依赖,该服务用于处理JWT令牌。
  3. doFilterInternal 方法:
  • 这是过滤器的主要处理方法,它在每个HTTP请求到达时被调用。
  • 首先,它调用 tokenService.getLoginUser(request) 来尝试获取用户的登录信息。这可能包括用户的身份信息、权限等。
  • 然后,它检查当前安全上下文中是否已经有了认证信息(SecurityUtils.getAuthentication())。如果没有认证信息,并且 loginUser 不为空,说明用户需要进行身份认证。
  • 接下来,它调用 tokenService.verifyToken(loginUser) 来验证JWT令牌的有效性。
  • 如果JWT令牌有效,它创建一个 UsernamePasswordAuthenticationToken 对象,该对象包含了用户信息和权限信息,并将该认证对象设置到安全上下文中。
  • 最后,它通过 chain.doFilter(request, response) 继续处理HTTP请求的其余部分,允许请求继续被处理。
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
{@Autowiredprivate TokenService tokenService;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws ServletException, IOException{LoginUser loginUser = tokenService.getLoginUser(request);if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication())){tokenService.verifyToken(loginUser);UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));SecurityContextHolder.getContext().setAuthentication(authenticationToken);}chain.doFilter(request, response);}
}
AuthenticationEntryPointImpl

用于处理未经身份验证用户的访问请求,它决定了在用户尝试访问需要身份认证的资源时应采取的操作
主要实现流程

  1. 调用commence方法,处理未经授权访问用户的请求
  2. 设置HTTP响应状态码为UNAUTHORIZED
  3. 返回未授权消息
LogoutSuccessHandlerImpl

用于处理用户成功退出(注销)应用程序时的逻辑,它定义了用户注销成功后应采取的操作

  1. 调用onLogoutSuccess方法,处理用户成功登出后响应
  2. 调用getLoginUser方法确认用户目前是存在的,且已经登录
  3. 删除当前用户缓存数据,记录用户注销信息到日志
  4. 反馈注销成功响应JSON

TokenService

TokenService 用于处理令牌(Token)的生成、验证和管理。这个服务通常用于实现用户身份认证和授权,以及管理用户会话信息。

  1. getLoginUser 方法:这个方法用于获取用户的身份信息。它首先尝试从请求中获取令牌,然后解析令牌以获取用户信息。如果解析成功,它将返回用户信息,否则返回 null
  2. setLoginUser 方法:这个方法用于设置用户的身份信息,通常在用户登录成功后调用。它会生成令牌、设置用户代理信息并刷新令牌有效期。
  3. delLoginUser 方法:这个方法用于删除用户的身份信息,通常在用户退出登录后调用。它会根据令牌来删除用户的缓存记录。
  4. createToken 方法:这个方法用于创建令牌。它生成一个随机的令牌,将用户信息和自定义的声明(claims)添加到令牌中,并使用秘钥对令牌进行签名。最后,它返回生成的令牌。
  5. verifyToken 方法:这个方法用于验证令牌的有效期。如果令牌的有效期距离过期不足20分钟,它会自动刷新令牌的缓存记录,以延长令牌的有效期。
  6. refreshToken 方法:这个方法用于刷新令牌的有效期。它会更新用户的登录时间和令牌有效期,并将用户信息存储到缓存中。
  7. setUserAgent 方法:这个方法用于设置用户代理信息,包括用户的IP地址、登录位置、浏览器和操作系统信息。这些信息通常用于审计和安全记录。
  8. createTokenparseToken 方法:这些私有方法用于生成和解析JWT令牌。createToken 方法用于生成令牌,而 parseToken 方法用于从令牌中提取数据声明。
  9. 其他辅助方法用于从令牌中获取用户名、获取请求中的令牌,以及构建缓存中的用户键。

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

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

相关文章

oracle 将数据库中聚合的id按指定的符号分割后合并为一列

在这里插入图片描述 数据库中存在这样的数据是clob字段并且是多个先将其拆分聚合为一列成 SELECT distinct REGEXP_SUBSTR(to_char(p.ids), [^;], 1, LEVEL) AS id FROM xxxxx p CONNECT BY REGEXP_SUBSTR(to_char(p.ids), [^;], 1, LEVEL) IS NOT NULL

力扣第62题 不同路径 c++ 动态规划 dp二维 + dp一维 解法

题目 62. 不同路径 中等 相关标签 数学 动态规划 组合数学 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Fini…

【QT】鼠标常用事件

新建项目 加标签控件 当鼠标进去&#xff0c;显示【鼠标进入】&#xff0c;离开时显示【鼠标离开】 将QLable提升成自己的控件&#xff0c;然后再去捕获 添加文件 改继承的类名 提升类 同一个父类&#xff0c;可以提升 效果 现在代码就和Qlabel对应起来了。 在.h中声明&…

科研迷雾:读研以来,我发现的科研界“怪象”

1 引言 随着读论文和做实验的增多&#xff0c;我发现了sci的很多猫腻经不起细细推敲&#xff0c;原来科研并不如我想象的神圣&#xff0c;还不如工业界来的实在&#xff0c;因为在工业界做项目出现问题&#xff0c;客户是验收不了不给付钱的。所以论文只是一个玩具。 2 常见的…

大数据预处理与采集实验三:Urllib的GET和POST请求(1)

目录 Urllib基本操作-GET ➢没有进行utf-8编码的输出 ➢经过utf-8decode之后的输出 ➢ Timeout参数&#xff1a;捕获由于连接超时而引发的异常 ◆Urllib基本操作-定制请求头 ➢ 在GET请求中加入多个访问参数 ◆Urllib基本操作-POST ➢有道词典网页爬取&#xff1a;找到…

libpcap获取数据包

一、用户空间 以Linux以及TPACKET_V3为例。 调用pcap_dispatch获取数据包&#xff0c;然后回调用户传递的数据包处理函数。 read_op实际调用的是pcap_read_linux_mmap_v3 // pcap.c int pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user) {return (p-…

钡铼技术助力ARM工控机在智慧交通中的创新应用

在交通运输领域&#xff0c;钡铼技术ARM工控机可以实现以下功能&#xff1a; 实时监控和管理&#xff1a;利用钡铼技术ARM工控机&#xff0c;可以对交通运输中的车辆、船只、飞机等进行实时监测和管理&#xff0c;帮助调度员提高车辆调度和路线规划的准确性和效率。 安全保障&…

Vue 3.0中Treeshaking特性是什么?

一、是什么 Tree shaking 是一种通过清除多余代码方式来优化项目打包体积的技术&#xff0c;专业术语叫 Dead code elimination 简单来讲&#xff0c;就是在保持代码运行结果不变的前提下&#xff0c;去除无用的代码 如果把代码打包比作制作蛋糕&#xff0c;传统的方式是把鸡…

js实现容器之间交换

&#x1f525;博客主页&#xff1a; 破浪前进 &#x1f516;系列专栏&#xff1a; Vue、React、PHP ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ JavaScript是一种非常流行和常用的编程语言&#xff0c;它在web开发中起着至关重要的作用&#xff0c;在实现网页动态交互、数据…

实时检测并识别视频中的汽车车牌

对于基于摄像头监控的安全系统来说,识别汽车牌照是一项非常重要的任务。我们可以使用一些计算机视觉技术从图像中提取车牌,然后我们可以使用光学字符识别来识别车牌号码。在这里,我将引导您完成此任务的整个过程。 要求: import cv2import numpy as npfrom skimage impor…

黑马 小兔鲜儿 uniapp 小程序开发- 商品详情模块- day05

黑马 小兔鲜儿 uniapp 小程序开发- 分类模块- day04-CSDN博客 小兔鲜儿 - 商品详情(登录前)-day05 商品详情页分为两部分讲解&#xff1a; 登录前&#xff1a;展示商品信息&#xff0c;轮播图交互&#xff08;当前模块&#xff09;登录后&#xff1a;加入购物车&#xff0c;立…

Xcode中如何操作Git

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的编码爱好者 大家好&#xff0c;我是 DevO…

[云原生案例1.] 构建LNMP架构并运行Wordpress个人博客平台

文章目录 1. 当前需求2. 前置准备3. 搭建过程3.1 创建自定义网络3.2 部署并配置nginx3.2.1 创建工作目录并上传相关软件包3.2.2 解压缩相关软件包3.2.3 编写Dockerfile文件3.2.4 编写nginx.conf文件3.2.5 创建nginx镜像3.2.6 运行容器 3.3 部署并配置mysql3.3.1 创建工作目录3.…

Python机器学习基础(二)---数据可视化

一.简单图形生成 1.Pandas生成折线图 import pandas as pd import numpy as np from matplotlib import pyplot #生成10行4列 标准正态分布的数据 df pd.DataFrame(np.random.randn(10,4),indexpd.date_range(1/1/2000,periods10), columnslist(ABCD)) df.plot() print(np.r…

分布式理论和分布式锁知识点总结

文章目录 (一) 分布式理论算法和协议1&#xff09;CAP理论总结 2&#xff09;BASE理论BASE 理论的核心思想基本可用软状态最终一致性 3&#xff09;Paxos算法Basic Paxos 算法4&#xff09; Raft算法1 拜占庭将军 5&#xff09;Gossip协议 (二) 分布式锁分布式锁应该具备哪些条…

89 柱状图中最大的矩形

柱状图中最大的矩形 类似接雨水&#xff08;反过来&#xff0c;相当于找接雨水最少的一段&#xff09;题解1 暴力搜索&#xff08;超时&#xff09; O ( N 2 ) O(N^2) O(N2)另一种 题解2 单调栈【重点学习】常数优化 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的…

看完这个,别说你还找不到免费好用的配音软件

有很多小伙伴还在找配音工具&#xff0c;今天就给大家一次性分享四款免费好用的配音工具&#xff0c;每一个都经过测试&#xff0c;并且是我们自己也在用的免费配音工具 第一款&#xff0c;悦音配音工具 拥有强悍的AI智能配音技术&#xff0c;更专业&#xff0c;完美贴近真人配…

算法升级之路(六)

给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例 1: 输入: numRows 5 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]] 示例 2: 输入: numRows 1 输出: [[1]] 解题思路&…

Spring IOC - ConfigurationClassPostProcessor源码解析

上文提到Spring在Bean扫描过程中&#xff0c;会手动将5个Processor类注册到beanDefinitionMap中&#xff0c;其中ConfigurationClassPostProcessor就是本文将要讲解的内容&#xff0c;该类会在refresh()方法中通过调用invokeBeanFactoryPosstProcessors(beanFactory)被调用。 5…

php收发邮件的多种方法?

1、添加扩展&#xff1a; # 第一种&#xff1a; composer require php-imap/php-imap # 第二种&#xff1a; composer require phpmailer/phpmailer2、这里采用第二种方式&#xff1a; <?php declare(strict_types1);namespace App\Controller\v1\email;use App\Controll…