java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > spring security 配置使用

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

作者:猩火燎猿

本文详细介绍了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();
}

五、官方文档与参考

六、进阶配置与应用

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 攻击

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

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

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

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

5. 方法级安全进阶

使用方式:

@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)

七、Spring Security 与 OAuth2、SSO 等整合

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

八、调试与排错建议

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

总结

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

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

您可能感兴趣的文章:
阅读全文