Spring Security 是一个强大且可扩展的框架,用于保护 Java 应用程序,尤其是基于 Spring 的应用。它提供了身份验证(验证用户身份)、授权(管理用户权限)和防护机制(如 CSRF 保护和防止会话劫持)等功能。
Spring Security 允许开发者通过机动的设置实现安全控制,确保应用程序的数据和资源安全。通过与其他 Spring 生态系统的无缝集成,Spring Security 成为构建安全应用的理想选择。
核心概念
- 身份验证 (Authentication): 验证用户的身份(比方,用户名/密码)。
- 授权 (Authorization): 确定用户是否有权限访问特定资源。
- 安全上下文 (Security Context): 存储已认证用户的详细信息,应用程序中可以访问。
1、预备工作
1.1 引入依靠
当我们引入 security 依靠后,访问需要授权的 url 时,会重定向到 login 页面(security 自己创建的),login 页面需要账号密码,账号默认是 user, 密码是随机的字符串,在spring项目标输出信息中
- spring-boot-starter-security
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-security</artifactId>
- <version>3.3.4</version>
- </dependency>
复制代码 - jjwt-api
- <dependency>
- <groupId>io.jsonwebtoken</groupId>
- <artifactId>jjwt-api</artifactId>
- <version>0.12.6</version>
- </dependency>
复制代码 - jjwt-impl
- <dependency>
- <groupId>io.jsonwebtoken</groupId>
- <artifactId>jjwt-impl</artifactId>
- <version>0.12.6</version>
- <scope>runtime</scope>
- </dependency>
复制代码 - jjwt-jackson
- <dependency>
- <groupId>io.jsonwebtoken</groupId>
- <artifactId>jjwt-jackson</artifactId>
- <version>0.12.6</version>
- <scope>runtime</scope>
- </dependency>
复制代码 一般我们会创建一个 SecurityConfig 类,来管理我们所有与 security 相干的设置。(我们讲的是 security 5.7 版本之后的设置方法,之前的方法跟现在不太一样)- @Configuration
- @EnableWebSecurity // 该注解启用 Spring Security 的 web 安全功能。
- public class SecurityConfig {
- }
复制代码 下面的都要写到 SecurityConfig 类中
1.2 用户认证的设置
基于内存的用户认证
通过 createUser , manager 把用户设置的账号密码添加到spring的内存中, InMemoryUserDetailsManager 类中有一个 loadUserByUsername 的方法通过账号(username)从内存中获取我们设置的账号密码,之后调用其他方法来判定前端用户输入的密码和内存中的密码是否匹配。- @Bean
- public UserDetailsService userDetailsService() {
- // 创建基于内存的用户信息管理器
- InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
-
- manager.createUser(
- // 创建UserDetails对象,用于管理用户名、用户密码、用户角色、用户权限等内容
- User.withDefaultPasswordEncoder().username("user").password("user123").roles("USER").build()
- );
- // 如果自己配置的有账号密码, 那么上面讲的 user 和 随机字符串 的默认密码就不能用了
- return manager;
- }
复制代码 当我们点进 InMemoryUserDetailsManager 中 可以发现它实现了 UserDetailsManager 和 UserDetailsPasswordService 接口,其中 UserDetailsManager 接口继承的 UserDetailsService 接口中就有 loadUserByUsername 方法
基于数据库的用户认证
上面讲到,spring security 是通过 loadUserByUsername 方法来获取 User 并用这个 User 来判定用户输入的密码是否精确。所以我们只需要继承 UserDetailsService 接口并重写 loadUserByUsername 方法即可
下面的样例我用的 mybatis-plus 来查询数据库中的 user, 然后通过当前查询到的 user 返回特定的 UserDetails 对象- @Service
- public class UserDetailsServiceImpl implements UserDetailsService {
- @Autowired
- UserMapper userMapper;
- @Override
- public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
- QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
- queryWrapper.eq("username", username); // 这里不止可以用username,你可以自定义,主要根据你自己写的查询逻辑
- User user = userMapper.selectOne(queryWrapper);
- if (user == null) {
- throw new UsernameNotFoundException(username);
- }
- return new UserDetailsImpl(user); // UserDetailsImpl 是我们实现的类
- }
- }
复制代码 UserDetailsImpl 是实现了 UserDetails 接口的类。UserDetails 接口是 Spring Security 身份验证机制的基础,通过实现该接口,开发者可以界说自己的用户模型,并提供用户相干的信息,以便进行身份验证和权限查抄。
[code]@Data@AllArgsConstructor@NoArgsConstructor // 这三个注解可以帮我们自动生成 get、set、有参、无参构造函数public class UserDetailsImpl implements UserDetails { private User user; // 通过有参构造函数填充赋值的 @Override public Collection |