spring security的基本原理、配置使用方式

 更新时间:2025年12月30日 14:49:48   作者:猩火燎猿  
本文详细介绍了SpringSecurity的基本原理、配置方式、常见使用场景以及常见问题的解决方法,还介绍了SpringSecurity与OAuth2、SSO等系统的整合,并提供了调试与排错建议,感兴趣的朋友跟随小编一起看看吧

一、Spring Security 基本原理

Spring Security 主要通过一系列过滤器链(Filter Chain)来实现安全控制。核心流程如下:

  1. 请求进入过滤器链(如 UsernamePasswordAuthenticationFilterBasicAuthenticationFilter 等)。
  2. 认证管理:通过 AuthenticationManager 进行身份认证。
  3. 授权管理:通过 AccessDecisionManager 判断当前用户是否有权限访问资源。
  4. 异常处理:如认证失败、权限不足等。

二、Spring Security 配置方式

1. 依赖引入

如果是 Spring Boot 项目,只需在 pom.xml 添加:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

2. 基本配置类(推荐方式:Java Config)

创建一个配置类,继承 WebSecurityConfigurerAdapter(Spring Security 5.7+ 推荐实现 SecurityFilterChain Bean)。

方式一:使用WebSecurityConfigurerAdapter(旧版)

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests() // 配置授权规则
                .antMatchers("/public/**").permitAll() // 允许所有人访问
                .antMatchers("/admin/**").hasRole("ADMIN") // 仅ADMIN角色可访问
                .anyRequest().authenticated() // 其他请求需认证
            .and()
            .formLogin() // 使用表单登录
                .loginPage("/login") // 自定义登录页
                .permitAll()
            .and()
            .logout()
                .permitAll();
    }
}

方式二:使用SecurityFilterChainBean(推荐)

@Configuration
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .antMatchers("/public/**").permitAll()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .formLogin(form -> form
                .loginPage("/login")
                .permitAll()
            )
            .logout(logout -> logout.permitAll());
        return http.build();
    }
}

3. 用户认证配置

可以自定义用户信息来源,比如内存、数据库等。

内存用户配置

@Bean
public InMemoryUserDetailsManager userDetailsService() {
    UserDetails user = User.withDefaultPasswordEncoder()
        .username("user")
        .password("password")
        .roles("USER")
        .build();
    UserDetails admin = User.withDefaultPasswordEncoder()
        .username("admin")
        .password("admin")
        .roles("ADMIN")
        .build();
    return new InMemoryUserDetailsManager(user, admin);
}

自定义UserDetailsService(如从数据库读取用户)

@Service
public class MyUserDetailsService implements UserDetailsService {
    @Autowired
    private UserRepository userRepository;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserEntity user = userRepository.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("User not found");
        }
        return new User(user.getUsername(), user.getPassword(), getAuthorities(user));
    }
    private Collection<? extends GrantedAuthority> getAuthorities(UserEntity user) {
        // 根据实际情况返回角色列表
        return AuthorityUtils.createAuthorityList("ROLE_USER");
    }
}

4. 常见功能配置

1. 禁用 CSRF(开发调试时可用,生产建议开启)

http.csrf().disable();

2. 配置静态资源免认证

.authorizeRequests()
    .antMatchers("/css/**", "/js/**", "/images/**").permitAll()

3. 配置自定义登录成功/失败处理

.formLogin()
    .successHandler(mySuccessHandler)
    .failureHandler(myFailureHandler)

4. 配置 Remember-Me 功能

.rememberMe()
    .tokenValiditySeconds(86400)
    .key("mySecretKey")

三、常见使用场景举例

1. RESTful 接口安全(无状态)

http
    .csrf().disable()
    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    .and()
    .authorizeRequests()
        .antMatchers("/api/public/**").permitAll()
        .anyRequest().authenticated()
    .and()
    .httpBasic();

2. 角色和权限控制

.authorizeRequests()
    .antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
    .antMatchers("/admin/**").hasRole("ADMIN")

3. 方法级安全

开启注解支持:

@EnableGlobalMethodSecurity(prePostEnabled = true)

在 Service 层方法上使用:

@PreAuthorize("hasRole('ADMIN')")
public void adminMethod() { ... }

四、常见问题

密码存储建议使用加密算法(如 BCrypt):

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}
  • 登录接口自定义返回 JSON:需自定义 AuthenticationSuccessHandler 和 AuthenticationFailureHandler
  • 前后端分离项目建议关闭 CSRF,并使用 JWT 或 Token 认证

五、官方文档与参考

六、进阶配置与应用

1. 自定义登录逻辑(前后端分离常用)

对于前后端分离项目,通常不使用 Spring Security 默认的表单登录,而是自定义登录接口,并返回 JSON 响应。

步骤:

1. 禁用默认登录页面和 CSRF

http
    .csrf().disable()
    .formLogin().disable();

2. 自定义登录接口
在 Controller 层实现登录接口,手动认证用户:

@RestController
public class AuthController {
    @Autowired
    private AuthenticationManager authenticationManager;
    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody LoginRequest loginRequest) {
        UsernamePasswordAuthenticationToken authToken =
            new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword());
        try {
            Authentication authentication = authenticationManager.authenticate(authToken);
            // 认证成功,生成 JWT 或返回用户信息
            return ResponseEntity.ok(/* token or user info */);
        } catch (AuthenticationException e) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("登录失败");
        }
    }
}

3. 配置 AuthenticationManager Bean

@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
    return configuration.getAuthenticationManager();
}

2. JWT(Json Web Token)整合

JWT 适用于前后端分离和 RESTful API 项目,实现无状态认证。

1. 依赖引入

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

2. JWT 工具类

public class JwtUtil {
    private static final String SECRET_KEY = "yourSecretKey";
    public static String generateToken(String username) {
        return Jwts.builder()
            .setSubject(username)
            .setIssuedAt(new Date())
            .setExpiration(new Date(System.currentTimeMillis() + 86400000))
            .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
            .compact();
    }
    public static String getUsernameFromToken(String token) {
        return Jwts.parser()
            .setSigningKey(SECRET_KEY)
            .parseClaimsJws(token)
            .getBody()
            .getSubject();
    }
}

3. JWT 过滤器
在 Spring Security 过滤器链中添加 JWT 校验:

public class JwtAuthenticationFilter extends OncePerRequestFilter {
    @Autowired
    private UserDetailsService userDetailsService;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        String token = request.getHeader("Authorization");
        if (token != null && token.startsWith("Bearer ")) {
            String jwt = token.replace("Bearer ", "");
            String username = JwtUtil.getUsernameFromToken(jwt);
            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                UsernamePasswordAuthenticationToken authToken =
                    new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                SecurityContextHolder.getContext().setAuthentication(authToken);
            }
        }
        chain.doFilter(request, response);
    }
}

4. 注册过滤器

http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

3. 异常处理(认证失败/权限不足)

1. 未认证异常处理

http.exceptionHandling()
    .authenticationEntryPoint((request, response, authException) -> {
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.getWriter().write("{\"error\":\"未认证\"}");
    });

2. 权限不足异常处理

.accessDeniedHandler((request, response, accessDeniedException) -> {
    response.setContentType("application/json;charset=UTF-8");
    response.setStatus(HttpServletResponse.SC_FORBIDDEN);
    response.getWriter().write("{\"error\":\"权限不足\"}");
});

4. 常见安全防护措施

1. 防止密码明文存储

始终使用加密算法存储密码,比如 BCrypt:

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

2. 防止 XSS/CSRF 攻击

  • 默认开启 CSRF,前后端分离项目建议关闭并采用 Token 防护。
  • 对输入内容进行过滤和转义。

3. 防止 Session Fixation(会话固定攻击)

http.sessionManagement()
    .sessionFixation().migrateSession();

4. 限制登录尝试次数(防暴力破解)

可结合 Redis、数据库等记录登录失败次数,超过阈值后锁定账号。

5. 方法级安全进阶

  • @Secured("ROLE_ADMIN")
  • @PreAuthorize("hasAuthority('sys:user:view')")
  • @PostAuthorize("returnObject.username == authentication.name")

使用方式:

@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)

七、Spring Security 与 OAuth2、SSO 等整合

Spring Security 支持与 OAuth2、OpenID Connect、CAS 等单点登录系统整合,具体可参考 Spring Security OAuth2 文档。

  • Spring Security OAuth2 Client:实现第三方登录(如微信、支付宝、GitHub)。
  • Spring Authorization Server:自建 OAuth2 授权服务。

八、调试与排错建议

  • 查看过滤器链
    • 可在启动日志中查找 FilterChainProxy,或通过断点调试。
  • 认证流程排查
    • 重点关注 UserDetailsServiceAuthenticationManagerPasswordEncoder 配置是否正确。
  • 权限控制问题

检查角色前缀(ROLE_)、方法注解是否生效。

总结

Spring Security 配置灵活、功能强大,推荐使用 Java 配置方式(即 SecurityFilterChain Bean),并根据实际需求自定义用户认证、授权、异常处理等。对于前后端分离、RESTful API 项目,建议使用无状态认证(如 JWT),并合理配置安全策略。

到此这篇关于spring security 配置使用的文章就介绍到这了,更多相关spring security 配置使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 深入解析Java中反射中的invoke()方法

    深入解析Java中反射中的invoke()方法

    最近复习了一下Java反射的使用,正好了解一下Java中反射中的invoke()方法,稍微整理精简一下做下分享,感兴趣的可以了解一下
    2021-06-06
  • SpringBoot实现图片上传及本地访问

    SpringBoot实现图片上传及本地访问

    在SpringBoot项目中,处理静态文件访问尤其是实时更新的文件如商品图片,可通过配置WebMvcConfig将本地文件映射到URL路径上,以解决重启项目才能访问文件的问题,本文详解如何保存和访问这些文件,帮助开发者优化项目文件管理
    2022-09-09
  • IDEA新手必备之各种快捷键详解

    IDEA新手必备之各种快捷键详解

    这篇文章主要介绍了IDEA新手必备之各种快捷键详解,文中有非常详细的快捷键介绍,对正在使用IDEA的小伙伴们有非常好的帮助,需要的朋友可以参考下
    2021-04-04
  • Java实现对象转CSV格式

    Java实现对象转CSV格式

    CSV是一种逗号分隔值格式的文件,一般用来存储数据的纯文本格式文件。Java对象转CSV,有现成的工具包,commons-lang3 的ReflectionToStringBuilder 就可以简单的解决的对象转CSV,快跟随小编一起学习一下吧
    2022-06-06
  • Java代码缺陷的自动化检测与跟踪的管理指南

    Java代码缺陷的自动化检测与跟踪的管理指南

    本文系统解析Java代码缺陷类型及危害,涵盖静态分析工具检测方法,动态监控技术(异常处理、性能指标),缺陷跟踪系统与CI/CD自动化集成方案,助力提升代码质量与安全防护,需要的朋友可以参考下
    2025-07-07
  • springboot实现将自定义日志格式存储到mongodb中

    springboot实现将自定义日志格式存储到mongodb中

    这篇文章主要介绍了springboot实现将自定义日志格式存储到mongodb中的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • Springboot Spring原理2深度解析

    Springboot Spring原理2深度解析

    SpringBoot的⾃动配置就是当Spring容器启动后, ⼀些配置类, bean对象等就自动存入到了IoC容器中,不需要我们手动去声明, 从而简化了开发, 省去了繁琐的配置操作,这篇文章介绍Springboot Spring原理2,感兴趣的朋友一起看看吧
    2025-11-11
  • SpringBoot3.x整合Swagger的过程及注意事项

    SpringBoot3.x整合Swagger的过程及注意事项

    Swagger是一个用于生成、描述、调用和可视化Restful风格的web服务的规范和完整框架,接下来通过本文给大家介绍
    2025-11-11
  • Java基础之Comparable与Comparator概述

    Java基础之Comparable与Comparator概述

    这篇文章主要介绍了Java基础之Comparable与Comparator详解,文中有非常详细的代码示例,对正在学习java基础的小伙伴们有非常好的帮助,需要的朋友可以参考下
    2021-04-04
  • springboot程序启动慢-未配置hostname的解决

    springboot程序启动慢-未配置hostname的解决

    这篇文章主要介绍了springboot程序启动慢-未配置hostname的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08

最新评论