Spring Security 如何实现身份认证和授权?

news/2024/11/8 16:39:38/

Spring Security 是一个开源的安全框架,提供了基于权限的访问控制、身份认证、安全性事件发布等功能。在 Spring Boot 应用中使用 Spring Security 可以非常方便地实现用户身份认证和授权。

Spring Security 实现身份认证的主要方式是使用认证过滤器链,该过滤器链包含多个过滤器,用于对用户进行身份验证和授权。在 Spring Security 中,认证和授权处理是通过过滤器链中的过滤器来实现的,最终返回一个认证成功的用户对象。本文将介绍 Spring Security 如何实现身份认证和授权,并提供示例代码。

在这里插入图片描述

1. Spring Security 的身份认证

Spring Security 的身份认证是通过 AuthenticationManager 接口实现的。AuthenticationManager 接口是一个认证管理器,用于对用户进行身份验证。在 Spring Security 中,AuthenticationManager 接口的默认实现是 ProviderManager。

ProviderManager 是一个认证管理器,它包含一个或多个 AuthenticationProvider 实现,用于对用户进行身份验证。AuthenticationProvider 接口是一个认证提供者,用于验证用户身份。在 Spring Security 中,AuthenticationProvider 的默认实现是 DaoAuthenticationProvider。

DaoAuthenticationProvider 是一个认证提供者,用于对用户进行身份验证。它需要一个 UserDetailsService 实现来获取用户信息和密码,然后使用 PasswordEncoder 进行密码校验。UserDetailsService 接口是一个用户详细信息服务接口,用于获取用户信息和密码。PasswordEncoder 接口是一个密码编码器接口,用于对密码进行编码和解码。

下面是一个基本的 Spring Security 配置示例,用于实现身份认证:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService userDetailsService;@Autowiredprivate PasswordEncoder passwordEncoder;@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/user/**").hasRole("USER").anyRequest().authenticated().and().formLogin().and().logout().and().csrf().disable();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);}}

在上面的代码中,使用 @EnableWebSecurity 注解启用 Spring Security。configure(HttpSecurity http) 方法用于配置访问控制,指定哪些 URL 需要哪些角色才能访问,以及任何请求都需要经过身份验证。formLogin() 方法启用基于表单的身份验证,logout() 方法启用注销支持,csrf().disable() 方法禁用 CSRF 保护。

configure(AuthenticationManagerBuilder auth) 方法用于配置身份验证,指定使用哪个 UserDetailsService 实现来获取用户信息和密码,以及使用哪个 PasswordEncoder 实现进行密码校验。

2. Spring Security 的授权

Spring Security 的授权是通过 AccessDecisionManager 接口实现的。AccessDecisionManager 接口是一个访问决策管理器,用于决定用户是否有权限访问某个资源。在 Spring Security 中,AccessDecisionManager 接口的默认实现是 AffirmativeBased。

AffirmativeBased 是一个访问决策管理器,它包含一个或多个 AccessDecisionVoter 实现,用于决定用户是否有权限访问某个资源。AccessDecisionVoter 接口是一个投票者,用于决定用户是否有权限访问某个资源。在 Spring Security 中,AccessDecisionVoter 的默认实现是 RoleVoter。

RoleVoter 是一个投票者,用于根据用户的角色决定用户是否有权限访问某个资源。在 Spring Security 中,我们可以通过实现 AccessDecisionVoter 接口来自定义投票者,根据自己的需求来决定用户是否有权限访问某个资源。

下面是一个基本的 Spring Security 配置示例,用于实现授权:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService userDetailsService;@Autowiredprivate PasswordEncoder passwordEncoder;@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/user/**").hasRole("USER").anyRequest().authenticated().and().formLogin().and().logout().and().csrf().disable();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);}

@Bean在上面的代码中,使用 @Bean 注解创建了一个自定义的 AccessDecisionVoter 实例,用于自定义投票逻辑。在 configure(HttpSecurity http) 方法中,通过 accessDecisionManager() 方法将自定义的 AccessDecisionVoter 实例添加到访问决策管理器中。

3. 完整的示例代码

下面是一个完整的 Spring Security 配置示例代码,用于实现身份认证和授权:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService userDetailsService;@Autowiredprivate PasswordEncoder passwordEncoder;@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/user/**").hasRole("USER").anyRequest().authenticated().and().formLogin().and().logout().and().csrf().disable().exceptionHandling().accessDeniedPage("/403");}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);}@Beanpublic AccessDecisionVoter<Object> accessDecisionVoter(){RoleHierarchyVoter roleHierarchyVoter = new RoleHierarchyVoter(roleHierarchy());return roleHierarchyVoter;}@Beanpublic RoleHierarchyImpl roleHierarchy() {RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");return roleHierarchy;}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}
}

在上面的代码中,使用 @EnableWebSecurity 注解启用 Spring Security。configure(HttpSecurity http) 方法用于配置访问控制,指定哪些 URL 需要哪些角色才能访问,以及任何请求都需要经过身份验证。formLogin() 方法启用基于表单的身份验证,logout() 方法启用注销支持,csrf().disable() 方法禁用 CSRF 保护,并且使用 accessDeniedPage() 方法指定访问被拒绝时跳转的页面。

configure(AuthenticationManagerBuilder auth) 方法用于配置身份验证,指定使用哪个 UserDetailsService 实现来获取用户信息和密码,以及使用哪个 PasswordEncoder 实现进行密码校验。

accessDecisionVoter() 方法创建了一个自定义的 AccessDecisionVoter 实例,用于自定义投票逻辑。在这个例子中,我们使用了 RoleHierarchyVoter 类实现了一个基于角色继承关系的投票逻辑。RoleHierarchyImpl 类用于定义角色继承关系。

passwordEncoder() 方法用于创建一个密码编码器实例,这里我们使用了 BCryptPasswordEncoder 类实现密码编码。

最后,我们需要实现 UserDetailsService 接口,用于获取用户信息和密码。下面是一个简单的实现示例:

@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate UserRepository userRepository;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user = userRepository.findByUsername(username).orElseThrow(() -> new UsernameNotFoundException("User not found with username: " + username));return new org.springframework.security.core.userdetails.User(user.getUsername(),user.getPassword(),user.getRoles().stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()));}
}

在上面的代码中,我们使用 UserRepository 类获取用户信息和密码,并将其包装成一个 UserDetails 实例返回。在这个例子中,我们使用了 org.springframework.security.core.userdetails.User 类实现了 UserDetails 接口。

结语

Spring Security 是一个非常强大的安全框架,可以为 Spring Boot 应用提供完整的身份认证和授权功能。本文介绍了 Spring Security 如何实现身份认证和授权,并提供了示例代码。使用 Spring Security 可以非常方便地保护应用程序,防止恶意攻击和数据泄露。


http://www.ppmy.cn/news/83231.html

相关文章

MySQL数据库中,在读已提交和可重复读这两个不同事务隔离级别下幻读的区别

目 录 1. 前 言1.1 并发事务存在的问题1.2 事务的隔离级别1.3 快照读和当前读 2. 不同事务隔离级别下幻读的区别2.1 读已提交下的幻读2.2 可重复读下的幻读2.2.1 情况一&#xff0c;无幻读2.2.2 情况二&#xff0c;有幻读2.2.3 情况三&#xff0c;有幻读 3. 小 结 1. 前 言 在…

基于 Prometheus 的 SLO告警实战

Prometheus是一个流行的开源监控系统&#xff0c;它可以帮助我们收集、存储和查询应用程序或系统的时间序列数据。在使用Prometheus进行监控时&#xff0c;通常需要根据服务水平指标&#xff08;Service Level Objectives&#xff0c;简称SLO&#xff09;来设置告警规则。 SLO…

linux学习[11]磁盘与文件系统(2):lsblkblkidpartedfdiskgdiskmkfs

文章目录 前言&#xff1a;1. 磁盘容量1.1 lsblk1.2 blkid1.3 parted 2. 磁盘分区2.1 fdisk/gdisk2.2 磁盘分区实例参考&#xff1a; 3. 磁盘格式化3.1 mkfs.xfs3.2 mkfs.ext43.3 mkfs.vfat 总结&#xff1a; 前言&#xff1a; 写了VMware的磁盘扩容之后&#xff0c;磁盘分区格…

标签派单系统架构设计

需求描述 项目背景 根据员工历史成单情况&#xff0c;计算员工对不同类型工单的转化能力。根据员工和工单标签匹配进行派单。 业务流程图 规则描述 每10分钟&#xff0c;分城进行一次派单&#xff0c;派单规则可能会动态删减&#xff0c;需要支持动态配置 工单标签说明 一…

Nginx Web页面缓存 Rsync远程同步

Nginx Web页面缓存 在http块中加配置&#xff1a; proxy_cache_path /data/nginx/cache levels1:2 keys_zonemy_cache:10m max_size10g inactive60m use_temp_pathoff ##################################### path&#xff1a;强制参数&#xff0c;指定缓存文件的存放路径 …

Spring 条件组件注解:`@Conditional` 与 `@ConditionalOnBean`

Spring 条件组件注解&#xff1a;Conditional 与 ConditionalOnBean 文章目录 Spring 条件组件注解&#xff1a;Conditional 与 ConditionalOnBean一、Conditional 基本使用0、条件组件是在非条件组件注册之后再进行注册的1、概述2、代码演示3、Conditional 的优缺点 二、Condi…

cpp 类成员函数delete this 会发生什么?

如题 this 简介: 每个非静态的类成员函数默认参数都会压栈一个this&#xff0c;它指向的是调用改成员函数的对象, 也是就className的object this 被隐含声明为 className* const this&#xff1b; 1.意味着不能改变this的指向2.this是个右值,不能取地址 ,不能&this 那我…

2023年NOC大赛创客智慧编程赛项Python 复赛模拟题(一)

题目来自:NOC大赛创客智慧编程赛项Python 复赛模拟题(一) 第一题: 编写一个彩票游戏:随机生成一个不重复的五位数作为彩票号,游戏提示用户输入一个五位整数,然后根据下面的规则判断用户是否能赢得奖金,最后要求输出彩票号和奖金。 (1)若用户输入的数字和彩票的数字完…