Spring Security 入门

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: Spring Security 是 Spring 框架中的安全模块,提供强大的认证和授权功能,支持防止常见攻击(如 CSRF 和会话固定攻击)。它通过过滤器链拦截请求,核心概念包括认证、授权和自定义过滤器。配置方面,涉及密码加密、用户信息服务、认证提供者及过滤器链设置。示例代码展示了如何配置登录、注销、CSRF防护等。常见问题包括循环重定向、静态资源被拦截和登录失败未返回错误信息,解决方法需确保路径正确和添加错误提示逻辑。

Spring Security 是 Spring 框架中一个功能强大且灵活的安全模块。它为应用程序提供了强大的认证和授权功能,同时支持防止常见的安全攻击(如 CSRF 和会话固定攻击)。在开发 Web 应用程序时,理解和配置 Spring Security 是保障系统安全的关键。

一、Spring Security 的核心概念

1. 认证(Authentication)

认证是指验证用户的身份,即确认用户是谁。Spring Security 的认证过程包括以下几个步骤:

  1. 用户提交登录凭据(例如用户名和密码)。
  2. Spring Security 验证凭据的合法性。
  3. 认证成功后,生成一个 Authentication 对象,存储在 SecurityContextHolder 中。
示例:获取当前用户的信息

当用户登录成功后,Spring Security 会将认证信息存储在会话中,从而在后续请求中验证用户身份。

ini

代码解读

复制代码

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.isAuthenticated()) {
    System.out.println("当前用户:" + authentication.getName());
}

2. 授权(Authorization)

授权是指在用户认证成功后,判断其是否有权限访问特定资源。Spring Security 通过角色(Role)或权限(Authority)来控制用户的访问行为。

示例:基于角色的访问控制

用户登录后,如果角色为 ROLE_ADMIN,可以访问管理页面;否则,将被重定向到权限不足的页面。

less

代码解读

复制代码

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/admin/**").hasRole("ADMIN") // 仅允许 ADMIN 角色访问
                .anyRequest().authenticated())
            .formLogin(form -> form
                .loginPage("/login")
                .defaultSuccessUrl("/home", true)
                .permitAll())
            .exceptionHandling(e -> e
                .accessDeniedPage("/access-denied")); // 权限不足跳转页面
        return http.build();
    }
}

3. 过滤器链(Security Filter Chain)

Spring Security 的工作原理是通过一组过滤器(Filter)来拦截和处理请求,这些过滤器形成了一个过滤器链。

关键过滤器及其职责

Spring Security 的过滤器链由多个过滤器组成,每个过滤器承担特定的职责。以下是部分关键过滤器的介绍:

  • UsernamePasswordAuthenticationFilter:专门处理用户的用户名和密码认证请求。
  • SecurityContextPersistenceFilter:负责维护用户的安全上下文信息,在每个请求开始时加载上下文,在请求完成时存储上下文。
  • CsrfFilter:用于防止跨站请求伪造攻击(CSRF),通过生成和验证 CSRF Token 来保护应用安全。
  • ExceptionTranslationFilter:捕获过滤器链中的异常,并将其转换为用户友好的响应。
示例:添加自定义过滤器

以下代码展示了如何在自定义过滤器链中插入额外的过滤器:

java

代码解读

复制代码

@Configuration
@EnableWebSecurity
public class CustomSecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.addFilterBefore(new CustomFilter(), UsernamePasswordAuthenticationFilter.class)
            .authorizeHttpRequests(auth -> auth
                .anyRequest().authenticated())
            .csrf().disable();

        return http.build();
    }

    private static class CustomFilter extends GenericFilterBean {
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            System.out.println("Custom filter applied");
            chain.doFilter(request, response);
        }
    }
}

二、Spring Security 的基本配置

在 Spring Boot 中,Spring Security 的配置主要通过以下几部分实现:

1. PasswordEncoder(密码加密器)

PasswordEncoder 用于对用户密码进行加密和验证。在 Spring Security 中,推荐使用 BCryptPasswordEncoder

java

代码解读

复制代码

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}
示例:密码加密与验证
  • 加密密码

java

  • 代码解读
  • 复制代码
String rawPassword = "123456";
String encodedPassword = passwordEncoder().encode(rawPassword);
System.out.println(encodedPassword); // 输出加密后的密码
  • 验证密码

java

  • 代码解读
  • 复制代码
boolean matches = passwordEncoder().matches("123456", encodedPassword);
System.out.println(matches); // true

2. UserDetailsService(用户信息服务)

UserDetailsService 是一个接口,用于从数据库加载用户信息(用户名、密码、角色等)。我们需要实现它,并在自定义逻辑中查询用户。

java

代码解读

复制代码

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("用户不存在"));
        return new org.springframework.security.core.userdetails.User(
                user.getUsername(),
                user.getPassword(),
                user.getRoles() // 用户角色
        );
    }
}

3. DaoAuthenticationProvider(认证提供者)

DaoAuthenticationProvider 是 Spring Security 的默认认证提供者。它依赖于 UserDetailsServicePasswordEncoder

java

代码解读

复制代码

@Bean
public DaoAuthenticationProvider authenticationProvider() {
    DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
    authProvider.setUserDetailsService(userDetailsService);
    authProvider.setPasswordEncoder(passwordEncoder());
    return authProvider;
}

4. SecurityFilterChain(过滤器链配置)

Spring Security 的过滤器链通过 SecurityFilterChain 进行配置。以下是常见配置项的解析:

4.1 CSRF(跨站请求伪造防护)

在开发阶段,可以禁用 CSRF 防护:

java

代码解读

复制代码

.csrf(csrf -> csrf.disable())

在生产环境,建议开启 CSRF 防护,并为特定接口添加白名单:

java

代码解读

复制代码

.csrf(csrf -> csrf.ignoringRequestMatchers("/api/**"))
4.2 授权规则

通过 authorizeHttpRequests 配置路由访问规则:

java

代码解读

复制代码

.authorizeHttpRequests(auth -> auth
        .requestMatchers("/login", "/register", "/css/**", "/js/**").permitAll()
        .anyRequest().authenticated()
)
4.3 自定义登录页面

通过 formLogin 配置自定义登录行为:

java

代码解读

复制代码

.formLogin(form -> form
        .loginPage("/login")                // 登录页面路径
        .loginProcessingUrl("/perform_login") // 登录表单提交路径
        .defaultSuccessUrl("/home", true)    // 登录成功后跳转页面
        .failureUrl("/login?error")         // 登录失败后跳转页面
        .permitAll()
)
4.4 注销配置

通过 logout 配置用户退出登录后的行为:

java

代码解读

复制代码

.logout(logout -> logout
        .logoutUrl("/logout")                  // 退出登录 URL
        .logoutSuccessUrl("/login?logout")     // 退出成功后跳转页面
        .permitAll()
)
4.5 会话管理

限制每个用户只能有一个会话,并配置会话过期后的行为:

java

代码解读

复制代码

.sessionManagement(session -> session
        .maximumSessions(1)                // 每个用户限制一个会话
        .expiredUrl("/login?expired")     // 会话过期后跳转页面
)

三、完整代码示例

以下是一个完整的 Spring Security 配置类示例:

java

代码解读

复制代码

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final UserDetailsServiceImpl userDetailsService;

    public SecurityConfig(UserDetailsServiceImpl userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService);
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .csrf(csrf -> csrf.disable())
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/login", "/register", "/css/**", "/js/**").permitAll()
                        .anyRequest().authenticated()
                )
                .formLogin(form -> form
                        .loginPage("/login")
                        .loginProcessingUrl("/perform_login")
                        .defaultSuccessUrl("/home", true)
                        .failureUrl("/login?error")
                        .permitAll()
                )
                .logout(logout -> logout
                        .logoutUrl("/logout")
                        .logoutSuccessUrl("/login?logout")
                        .permitAll()
                )
                .authenticationProvider(authenticationProvider())
                .sessionManagement(session -> session
                        .maximumSessions(1)
                        .expiredUrl("/login?expired")
                );
        return http.build();
    }
}

四、常见问题与排查

1. 登录后页面循环重定向

  • 问题:登录成功后,页面无限跳转。
  • 原因:登录页面路径和默认跳转页面相同,导致循环跳转。
  • 解决方案: 确保 defaultSuccessUrlloginPage 的路径不同。

2. 静态资源被拦截

  • 问题:CSS 或 JavaScript 文件无法加载。
  • 原因:静态资源路径未被放行。
  • 解决方案: 确保在 authorizeHttpRequests 中添加以下规则:

java

  • 代码解读
  • 复制代码
.requestMatchers("/css/**", "/js/**", "/images/**").permitAll()

3. 登录失败未返回错误信息

  • 问题:用户登录失败时,未显示具体错误提示。
  • 解决方案: 确保在登录页面中添加错误信息的展示逻辑:

html

  • 代码解读
  • 复制代码
<div th:if="${param.error}" class="error">用户名或密码错误</div>


转载来源:https://juejin.cn/post/7449886016058228755

目录
打赏
0
2
2
0
195
分享
相关文章
Spring Cloud Alibaba AI 入门与实践
本文将介绍 Spring Cloud Alibaba AI 的基本概念、主要特性和功能,并演示如何完成一个在线聊天和在线画图的 AI 应用。
554 7
Spring5入门到实战------17、Spring5新功能 --Nullable注解和函数式注册对象。整合JUnit5单元测试框架
这篇文章介绍了Spring5框架的三个新特性:支持@Nullable注解以明确方法返回、参数和属性值可以为空;引入函数式风格的GenericApplicationContext进行对象注册和管理;以及如何整合JUnit5进行单元测试,同时讨论了JUnit4与JUnit5的整合方法,并提出了关于配置文件加载的疑问。
Spring5入门到实战------17、Spring5新功能 --Nullable注解和函数式注册对象。整合JUnit5单元测试框架
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
Spring Boot 入门:简化 Java Web 开发的强大工具
Spring Boot 是一个开源的 Java 基础框架,用于创建独立、生产级别的基于Spring框架的应用程序。它旨在简化Spring应用的初始搭建以及开发过程。
126 7
Spring Boot 入门:简化 Java Web 开发的强大工具
如何用Spring Boot实现拦截器:从入门到实践
如何用Spring Boot实现拦截器:从入门到实践
127 5
从入门到精通---深入剖析Spring DAO
在Java企业级开发中,Spring框架以其强大的功能和灵活性,成为众多开发者的首选。Spring DAO(Data Access Object)作为Spring框架中处理数据访问的重要模块,对JDBC进行了抽象封装,极大地简化了数据访问异常的处理,并能统一管理JDBC事务。本文将从概述、功能点、背景、业务点、底层原理等多个方面深入剖析Spring DAO,并通过多个Java示例展示其应用实践,同时指出对应实践的优缺点。
72 1
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中拦截器的入门教程和实战项目场景实现的详细指南。
72 0
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中过滤器的基础知识和实战项目应用的教程。
81 0
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】
文章是关于Spring、SpringMVC、Mybatis三个后端框架的超详细入门教程,包括基础知识讲解、代码案例及SSM框架整合的实战应用,旨在帮助读者全面理解并掌握这些框架的使用。
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】
Redis6入门到实战------ 八、Redis与Spring Boot整合
这篇文章详细介绍了如何在Spring Boot项目中整合Redis,包括在`pom.xml`中添加依赖、配置`application.properties`文件、创建配置类以及编写测试类来验证Redis的连接和基本操作。
Redis6入门到实战------ 八、Redis与Spring Boot整合

热门文章

最新文章