Spring Security功能概述和相关介绍

news/2025/2/25 12:12:55

Spring Security是基于Spring 和Spring MVC的声明式安全性框架,主要是为了给Java应用提供全面的安全解决方案,能够通过简洁的配置,实现了Web请求级别方法调用级别的身份验证与访问授权。它本身已充分使用了Spring容器,Spring AOP及spring过滤器等技术

Spring Security的核心特性

1.多层次的保护机制:

Web请求级别:通过过滤器(Filter Chain)拦截HTTP请求,确保只有经过认证和授权的用户才能访问受保护的资源

方法调用级别:通过Spring AOP在方法执行前进行权限检查,确保只有具备相应权限的用户才能执行特定操作

2.灵活的认证和授权

支持多种认证方式

    1.用户名密码验证

    2.LDAP认证

    3.OAuth2认证

提供基于角色,权限表达式等多种授权策略,满足不同场景的安全需求            

Spring Security的开发需要导入Spring-security-wed和spring -security-config模块,Maven的导入方式如下:

<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-web</artifactId>
  <version>${springsecurity.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework.security</groupId> 
  <artifactId>spring-security-config</artifactId>
  <version>${springsecurity.version}</version>
</dependency>

导入后,举一个简单实例了解Spring Security框架的大体使用,下面的实例使用Spring Security框架对index前缀的请求进行拦截和验证,开发包括两步:配置Spring Security的配置文件(这里的文件名为spring-security.xml)和配置web.xml文件

1.配置spring-security.xml

新建spring-security.xml文件,配置内容如下:

<!--默认的命名空间-->
<beans: beans xmshttp://www.springframework.org/schema/security
  xmins: beans=http://www.springframework.org/schema/beans
  xmins: xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi: schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/security
  http://www.springframework.org/schema/security/spring-security.xsd">
<beans:bean id="passwordEncoder" <-- 密码加密器-->  class="org.springframework.security.crypto.password. NoOpPassword Encoder" />
<http auto-config="true"><!--开启认证功能-->
<!--请求与权限-->
<intercept-ur1 pattern="/index*" access="hasRole ('ROLE_USER') " />
</http>
<authentication-manager><!--认证管理器—->
  <authentication-provider><!--认证器-->
     <user-service><!--内存用户与角色-->
       <user name="wukong" password="1" authorities="ROLE_USER" />
     </user-service>
  </authentication-provider>
</authentication-manager>
</beans:beans>

具体实现:ROLE_USER角色的登录用户才可以访问以index为前缀的地址。如果当前用户没有登录,则会转到安全框架内置的登陆页面

2.web.xml的配置

spring-security.xml添加到contextConfigLocation的上下文参数中,再配置名称为springSecurityFilterChain的过滤器及映射,配置片段如下:

<context-param>
  <!--核心与安全配置文件-->
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:application.ml, classpath:spring-security.
  xml</param-value>
</context-param>
<filter>
  <filter-name>springSecurityFilterChain</filter-name>
  <filter-class>org. springframework.web. filter. DelegatingFilterProxy </filter-class>
  </filter>
<filter-mapping>
  <filter-name>springSecurityFilterChain</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

以上配置完成后,启动服务器测试后访问系统主页,会自动弹出Spring Security框架自带的登录页面

配置认证管理器

通过这下面这两个标签配置认证管理器,用于管理用户的认证过程,确保只有经过身份验证的用户才能访问受保护的资源

  • </authentication-manager>:用于配置认证管理器的标签,负责处理用户的认证请求

当用户尝试登陆时,认证管理器会接收认证请求,并交由配置的认证提供者<authentication-provider>进行实际的身份验证

  •  <authentication-provider>(子标签)配置具体的认证器,认证器负责验证用户身份

通过配置用户信息服务,认证提供者可以加载用户信息(用户名,密码,权限等),认证成功后,给用户分配权限(authorities),用于后续的授权检查

用户信息服务:

内存用户存储:直接在配置文件中定义用户信息

<authentication-manager>
  <authentication-provider>
    <user-service>
    <!--配置内存中的用户-->
    <user name="wukong" password="1" authorities="ROLE_USER" />
    </user-service>
  </authentication-provider>
</authentication-manager>

数据库用户存储:从数据库中读取用户信息

<authentication-manager>
  <authentication-provider>
   <beans :bean id="userDetailService"
       class="com. osxm. daport. security UserDetailServiceImp1" />
   <security:authentication-manager><!--认证管理器-->
     ‹security:authentication-provider user-service-ref="userDetails Service" />
   </security: authentication-manager>
  </authentication-provider>
</ authentication-manager>

除了配置内存用户和数据库查询用户外,也可以继承UserDetailsService接口实现自定义的用户服务,实现loadUserByUsername()方法通过用户名获取UserDetails类型的用户账号对象

java">//自定义用户账号服务
public class UserDetailServiceImpl implements UserDetailsService {
   @Override
   public UserDetails loadUserByUsername (String userName)
        throws UsernameNotFoundException {
     List<GrantedAuthority> authsList = new ArrayList<GrantedAuthority> () ;
       authsList.add (new SimpleGrantedAuthority ("USER") ) ;
     User userdetail = new User ("Wukong", "1", authsList) ;
   return userdetail;
  }
} 

Spring Security密码加密

在存储用户密码时,直接存储明文密码非常不安全,容易被攻击者窃取,造成较严重的后果,Spring Security提供了密码加密机制,能够确保密码在存储时是加密的,即使数据库泄露,攻击者也无法直接获取用户的明文密码

Spring Security默认使用BCrypt加密算法,基于哈希的加密算法,这里演示使用BCryptPasswordEncoder加密器类进行加密,通过统一加密工厂PasswordEncoder-Factories获取加密器进行加密

如:这里对字符串“1”加密

java">//默认使用BCrypt算法
org.springframework.security.crypto.password.PasswordEncoder encoder = 
    PasswordEncoderFactories.createDelegatingPasswordEncoder();
String encryptPassword = encoder.encode("1");
/*encoder.encode("1"):调用PasswordEncoder的encode方法,
对明文密码“1”进行加密,返回加密后的字符串*/

以上对字符串“1”加密后的结果为

java">{bcrypt} $2a$10$1k6FdrtCay.RwPBZ6YncPunoiaPMW1F5aMigenOKm. WJC8YA. 3vYG

此外,Spring还提供了BCrypt工具类,可以更方便的使用BCrypt算法进行加密,调用方法如下:

java">import org.mindrot.jbcrypt.BCrypt;

public class BCryptExample {
    public static void main(String[] args) {
        // 1. 原始密码
        String originPassword = "123456";

        // 2. 生成盐值并加密密码
        String encryptPassword = BCrypt.hashpw(originPassword, BCrypt.gensalt());
        System.out.println("加密后的密码: " + encryptPassword);

        // 3. 验证密码
        boolean isMatch = BCrypt.checkpw(originPassword, encryptPassword);
        System.out.println("密码是否匹配: " + isMatch);
    }
}

结果:

java">加密后的密码: $2a$10$5vR5v5zX5zX5zX5zX5zX5u
密码是否匹配: true

 BCrypt加密的原理:

盐值(Salt):盐值是一个随机字符串,用于在加密过程中与密码结合,确保即使两个用户的密码相同,加密后的结果也不同

加密过程:BCrypt算法会将盐值与密码结合,经过多次哈希运算,生成了一个固定长度的加密字符串

另外除了不加密和bcrypt加密算法之外,Spring Security支持的加密算法及实现类还有以下

Spring Security支持的加密算法及加密器类

加密算法实现类
1bcryptBCryptPasswordEncoder
2MD4Md4PasswordEncoder
3MD5MessageDigestPasswordEncoder ("MD5")
4noopNoOpPasswordEncoder
5pbkdf2Pbkdf2PasswordEncoder
6scryptSCryptPasswordEncoder
7SHA-1MessageDigestPasswordEncoder ("SHA-1")
8SHA-256new MessageDigestPasswordEncoder("SHA-256")

Spring Security方法层级授权

通过Spring Security方法层级授权我们可以对代码中具体方法的调用进行权限校验,确保只有满足条件的用户或角色才能执行该方法

方法层级控制能够直接针对类或方法定义访问规则,如:

    只有管理员(ROLE_ADMIN)才能调用删除用户的方法

    普通用户(ROLE_USER)只能查询自己的数据

Spring Security使用Spring AOP实现方法层级的权限控制,使用方式有三种:

  • 使用<intercept-methods>标签对单个Bean的方法访问控制进行设定;
  • 在类和方法中使用Spring安全注解或JSP-250注解进行细粒度控制 
  • 使用<protect-pointcut>配置权限控制方法的切点;

1.单个Bean方法保护的配置

在Bean的配置中使用<intercept-methods>标签对当前Bean中的方法进行权限控制,示例对UserServiceImpl中以get开头的方法进行权限拦截,要求调用者必须具有ROLE_USER角色:

<!--定义了一个userService的Bean,对应实现类UserServiceImpl-->
<beans:bean id="userService" class="com.osxm.daport.service.impl.UserServiceImpl">
   <!--<intercpet-methods>表示对该Bean方法进行权限拦截-->
    <intercept-methods>  <!-- 拦截需要权限验证的方法 -->
        <protect access="ROLE_USER" method="get*" />
    </intercept-methods>
</beans:bean>

<protect>:定义权限规则

  1. method=”get*“:匹配所有以get开头的方法(如getUser,getProfile)
  2. access=”ROLE_USER“:只有具有ROLE_USER角色的用户才能调用这些方法

当用户尝试调用UserServiceImpl中任意以get开头的方法时,Spring Security会检查当前用户是否拥有ROLE_USER角色,如果未授权,将抛出AccessDeniedException

2.方法的安全注解

在类和方法中使用安全注解可以简化XML的配置,同时可以对方法进行更灵活的控制,Spring提供和支持的注解有三类:

JSR-250注解:

这是Java的标准安全注解,主要是@RelosAllowed

@RelosAllowed

该注解属于JSR-250注解,基于角色的简单权限控制,属于JavaEE标准的一部分,使用前需要导入了Java标准库Javax.annotation-api,使用Maven导入如下:

<dependency>
  <groupId>javax. annotation</groupId>
  <artifactId>javax.annotation-api</artifactid>
  <version >1.3.2</version>
</dependency>

@RelosAllowed注解可以使用在类和方法中,在注解后加上授权的角色,标注在类中时,该类所有方法的执行都需要对应的角色,如果同时使用在类和方法中,则方法中的注解会覆盖类中的注解,演示使用该注解对List方法进行权限控制,代码示例如下:

java">@RolesAllowed ("ROLE_USER")//允许 ROLE_USER角色的用户访问
public List<User> list (User user) {
    return userDao. list (user);
//调用userDao.list(user)查询用户列表,并返回结果
}

除了@RelosAllowed之外,JSR-250安全注解还有@PermitAll和@DenyAll

  • @PermitAll允许任何角色访问,也就是不控制权限
  • @DenyAll则是拒绝所有角色访问
  • @PermitAll和@DenyAll同样可以使用在类和方法中,如果一个方法同时使用了这两个注解,则先定义的有效;如果同时使用在类中则是相反,后定义的生效

@Secured:

Spring提供的​​​​​​一般性安全注解

 @Secured安全注解

@Secured注解在xml中先启动配置,用于启动@Secured注解支持

@Secured注解需要设置<global-method-security>标签的secured-annotations属性值为enabled才能开启

XML:

<global-method-security secured-annotations="enabled"/>

在类和方法中使用:

java">@Secured ("ROLE_USER")//只有拥有ROLE_USER角色的用户才能调用此方法
public List<User> list (User user) {
    return userDao. list (user);
}

Spring表达式驱动注解(更强大的控制):

支持基于SpEL(Spring Expression Language)的复杂权限逻辑

  • @PreAuthorize:在方法调用前检查权限
  • @PostAuthorize::在方法调用后检查权限,如果没有权限则无法返回结果
  • @PreFilter:在方法调用前对集合类型参数进行过滤
  • @PostFilter:在方法执行后,对集合类型的返回结果进行过滤

该类型注解先在xml中启动配置

XML:

<global-method-security pre-post-annotations="enabled" />

@PreAuthorize和@PostAuthorize用于方法调用前后进行权限检查,@PreFilter和@PostFilter则是对集合类型参数及返回值进行过滤

@PreAuthorize使用场景之一就是登录账号只能查询自己的账号信息

java">//认证账号只能查询自己的信息
@PreAuthorize ("principal. username. equals (#username) ")
@Override
public User get (String username){
return userdao. get (username) ;

@PostAuthorize使用在方法执行完成后的权限检查,该注解不控制该方法是否执行,只控制方法执行后的结果返回,如果表达式的结果为false则抛出AccessDeniedException异常

在@PreFilter和@PostFilter注解的表达式中,使用内置表达式变量filterObject对集合进行过滤

@PreFilter注解:

在方法执行前,对输入参数(比如集合或数组)进行过滤,仅保留满足条件的元素
代码演示:只取偶数的ID,排除奇数的ID

java">@PreFilter("filterObject % 2 == 0") //只取偶数的ID,排除奇数的ID
  public void delete (List< Integer> ids) {
    for (Integer id : ids) {
        userDao.delete(id);
    }
}

 filterObject是Spring Security提供的特殊变量,表示集合中的当前元素

@PostFilter注解:
在方法执行后,对返回值(比如集合或数组)进行过滤,仅保留满足条件的元素

java">//对返回结果过滤,只返回部门ID是1的用户
@PostFilter ("filterObject .deptId==1") 
public List<User> list (User user) {
   return userDao.list (user);
}
java">//授权对象
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("USER");
//授权列表
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority> () ;
authorities.add (grantedAuthority) ;//授权列表添加
//用户账号信息
UserDetails userDetails = new User("wukong","1",authorities);
UserDetailsService userDetailsService = new InMemoryUserDetailsManager
(userDetails) :
//DAO 类型认证器
DaoAuthenticationProvider provider = new DaoAuthenticationProvider ():
//设置认证器的用户信息服务
provider. setUserDetailsService (userDetailsService) ;
//设置认证器的加密器
provider. setPasswordEncoder (NoOpPasswordEncoder. getInstance ( )) ;
List<AuthenticationProvider > providers = new ArrayList<Authentication
Provider> () ;
providers. add (provider) ;
AuthenticationManager authenticationManager = new ProviderManager
(providers) ;

Spring Security的安全访问控制机制工作原理:

Spring Security的安全访问控制机制主要依赖Filter链实现,其核心原理是通过拦截HTTP请求,逐步执行一系列安全相关的过滤器(Filter),最终决定是否允许请求访问目标资源

当初始化Spring Security时,会创建一个名为SpringSecurityFilterChain的Servlet过滤器,类型为org.springframework.security.web.FilterChainProxy,它实现了Javax.servlet.Filter,因此外部的请求会经过此类,下图是Spring Security过滤器链结构图:

FilterChainProxy是一个代理,真正起作用的是FilterChainProxy中的SecurityFilterChain所包含的各个Filter,同时这些Filter作为Bean被Spring管理,它们是Spring Security核心,各有各的职责,但他们并不直接处理用户的认证,也不直接处理用户的授权,而是把它们交给了认证管理器(AuthenticationManager)和决策管理器(AccessDecisionManager)进行处理

Spring Security功能的实现主要是由一系列过滤器链相互配合完成

下面介绍过滤器链中主要的几个过滤器及其作用:

1.SecurityContextPersistenceFilter:这个Filter是整个拦截过程的入口和出口(也就是第一个和最后一个拦截器)

会在请求开始时从配置好的SecurityContextRepository(如 HTTP Session)中加载SecurityContext ,并将其设置到SecurityContextHolder中

在请求结束时,将SecurityContextHolder中的SecurityContext保存回SecurityContextRepository,并清除SecurityContextHolder中的内容

举例以下场景

用户登陆后,访问需要认证的页面(如/profile),系统从Session中恢复用户的认证信息

用户注销后,系统清除Session中的认证信息,确保用户无法继续访问受保护资源

2.UsernamePasswordAuthenticationFilter:专门处理基于表单的登录请求

能够从请求中提取用户名和密码,然后调用AuthenticationManager进行认证,根据认证结果,调用AuthenticationSuccessHandler 或AuthenticationFailureHandler 处理成功或失败。

举例以下场景

用户通过表单提交用户名和密码进行登录,系统验证用户名和密码是否正确,并根据结果跳转到成功页面或失败页面

3.FilterSecurityInterceptor:负责对Web资源进行访问控制

从 SecurityContextHolder 中获取当前用户的 Authentication 对象,调用 AccessDecisionManager 进行授权决策,根据决策结果,决定是否允许访问目标资源

举例以下场景

  • 管理员访问 /admin/dashboard 页面,系统检查用户是否具有 ADMIN 角色,如果有则允许访问,否则返回 403 错误
  • 普通用户尝试访问 /admin/dashboard 页面,系统返回 403 错误

4.ExceptionTranslationFilter :

能够捕获来自 FilterChain 所有的异常,并进行处理。但是它只会处理两类异常:AuthenticationException 和 AccessDeniedException,其它的异常它会继续抛出。

举例以下场景

  • 未登录用户访问受保护资源

    当用户未登录时访问受保护资源(如 /profile),系统捕获 AuthenticationException,并重定向到登录页。
  • 未授权用户访问受保护资源

    当用户登录后访问未授权资源(如 /admin/dashboard),系统捕获 AccessDeniedException,并返回 403 错误。

Spring Security的执行流程如下:

1.用户提交用户名,密码被SecurityFilterChain中的UsernamePasswordAuthenticationFilter过滤器获取到,封装为请求Authentication,通常情况下是UsernamePasswordAuthenticationToken这个实现类

2,然后过滤器将Authentication提交至认证管理器(AuthenticationManager)进行认证

3.认证成功后,AuthenticationManager身份管理器返回一个被填充满了的信息(包括上面提到的权限信息,身份信息,细节信息,但密码通常会被移除)Authentication实例

4.SecurityContextHolder安全上下文容器将第3步填充了的信息Authentication,通过SecurityContextHolder.getContext().setAuthentication(...)方法,设置到其中

5.可以看出AuthenticationManager接口(认证管理器)是认证相关的核心接口,也是发起认证的出发点,它的实现类为ProviderManager。而Spring Security支持多种认证方式,因此ProviderManager维护着一个List<AuthenticationProvider>列表,存放多种认证方式,最终实际的认证工作是由AuthenticationProvider完成的


http://www.niftyadmin.cn/n/5865484.html

相关文章

图数据库Neo4j面试内容整理-约束(Constraint)

约束(Constraint) 是数据库中用于确保数据一致性和完整性的一种机制。它限制了数据的某些方面,确保特定条件得到满足。在 Neo4j 中,约束主要用于确保图数据的一致性,防止插入不符合规则的数据。约束通常与索引一起使用,但它们的功能和目的有所不同。 1. Neo4j 中的约束类…

leetcode刷题-动态规划08

代码随想录动态规划part08|121. 买卖股票的最佳时机、122.买卖股票的最佳时机II、123.买卖股票的最佳时机III 121.买卖股票的最佳时机122.买卖股票的最佳时机II123.买卖股票的最佳时机III -- 困难 121.买卖股票的最佳时机 leetcode题目链接 代码随想录文档讲解 思路&#xff1a…

IOS基础面试题

1. 什么是MVC&#xff1f; MVC&#xff08;Model-View-Controller&#xff09;是一种常见的设计模式&#xff0c;用于组织代码 Model&#xff08;模型&#xff09;&#xff1a; 代表数据层&#xff0c;处理数据的逻辑。View&#xff08;视图&#xff09;&#xff1a; 负责展示…

vue2.x 中父组件通过props向子组件传递数据详细解读

1. 父组件向子组件传递数据的步骤 在子组件中定义 props&#xff1a; 子组件通过 props 选项声明它期望接收的数据。props 可以是数组形式&#xff08;简单声明&#xff09;或对象形式&#xff08;支持类型检查和默认值&#xff09;。 在父组件中使用子组件时绑定 props&#x…

Mac下VSCode调试skynet的lua环境配置

Mac下VSCode调试skynet的lua环境配置 安装Lua5.4安装Luasocket下载LuaPanda.lua安装VScode LuaPanda插件配置skynet&#xff0c;在lua_cpath引入luasocket库创建launch.json在需要调试的lua文件里面添加代码 安装Lua5.4 brew install lua5.4安装Luasocket LuaPanda需要luasoc…

IO进程 day05

IO进程 day05 9. 进程9. 9. 守护进程守护进程的特点守护进程创建步骤 10. 线程10.1. 线程的概念10.2. 进程和线程的区别10.2. 线程资源10.3. 线程的函数接口1. pthread_create-创建线程线程函数和普通函数的区别 2. pthread_exit3.线程资源回收函数join和detach的区别 获取线程…

Flink API 解析 Flink Job 依赖的checkpoint 路径

引言 之前写一篇 Python 脚本解析 Flink _metadata 中依赖的 checkpoint 路径文章 Python解析 Flink Job 依赖的checkpoint 路径 &#xff0c;代码比较暴力&#xff0c;直接按照 checkpoint 路径前缀判断&#xff0c;最近发现网上有通过 Flink API 解析 Flink Checkpoint 元数…

【JavaEE进阶】Spring Boot配置文件

欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗 如有错误&#xff0c;欢迎指出~ 目录 SpringBoot配置⽂件 举例: 通过配置文件修改端口号 配置⽂件的格式 properties基本语法 读取配置⽂件 properties配置文件的缺点 yml配置⽂件 yml基本语法 yml和proper…