使用SecurityFilterChain配置Spring Security端点权限:仅/hello需授权
Spring Boot 2.7.1 基于SecurityFilterChain的权限控制实现方案
需求回顾
/hello端点:需授权访问,未登录时自动跳转至Spring Security默认登录页/bye端点:禁止所有访问,直接返回401/403错误,无法调用
现有代码问题分析
- 权限规则缺失:当前配置仅限制了
/hello需认证,但/bye默认允许匿名访问,不符合需求 - 自定义认证逻辑未生效:
MyAuthenticationProvider未被Spring Security加载,无法替代默认认证流程 - 密码验证不规范:
MyAuthenticationProvider直接明文比较密码,与配置的BCryptPasswordEncoder安全规范冲突
修改后的完整代码
1. MySecurityConfig.java(核心配置调整)
package com.example.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.SecurityFilterChain; @Configuration public class MySecurityConfig { private final AuthenticationProvider myAuthenticationProvider; // 注入自定义认证提供者 public MySecurityConfig(AuthenticationProvider myAuthenticationProvider) { this.myAuthenticationProvider = myAuthenticationProvider; } @Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // 启用表单登录,未认证访问/hello时跳转默认登录页 http.formLogin() .and() // 指定使用自定义的认证逻辑 .authenticationProvider(myAuthenticationProvider) // 配置请求权限规则 .authorizeRequests() // /hello必须经过认证才能访问 .antMatchers("/hello").authenticated() // /bye直接拒绝所有请求(无论是否登录) .antMatchers("/bye").denyAll() // 其他请求默认允许(可根据实际需求调整) .anyRequest().permitAll(); return http.build(); } @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
2. MyAuthenticationProvider.java(密码验证优化)
import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; @Component public class MyAuthenticationProvider implements AuthenticationProvider { private final BCryptPasswordEncoder passwordEncoder; // 注入密码编码器 public MyAuthenticationProvider(BCryptPasswordEncoder passwordEncoder) { this.passwordEncoder = passwordEncoder; } @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String username = authentication.getName(); String password = authentication.getCredentials().toString(); // 示例硬编码用户,实际可替换为数据库查询逻辑 if ("john".equals(username)) { // 使用密码编码器验证,避免明文比较 if (passwordEncoder.matches(password, passwordEncoder.encode("12345"))) { // 给用户分配基础权限,避免认证后权限不足 List<GrantedAuthority> authorities = Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")); return new UsernamePasswordAuthenticationToken(username, null, authorities); } else { throw new BadCredentialsException("密码错误"); } } else { throw new BadCredentialsException("用户名不存在"); } } @Override public boolean supports(Class<?> authentication) { return authentication.equals(UsernamePasswordAuthenticationToken.class); } }
3. HelloController.java(无需修改)
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @GetMapping("/hello") public String hello() { return "Hello from Spring Security"; } @GetMapping("/bye") public String bye() { return "Bye"; } }
关键改动说明
- 权限规则调整:添加
.antMatchers("/bye").denyAll(),直接拒绝所有对/bye的请求,无论登录状态都返回403 Forbidden - 自定义认证生效:通过构造注入
MyAuthenticationProvider,并在HttpSecurity中指定使用该认证逻辑 - 密码安全优化:用
BCryptPasswordEncoder.matches()替代明文比较,符合安全规范 - 权限分配:给认证用户分配至少一个权限(如
ROLE_USER),避免认证后因权限不足导致访问异常
测试效果
- 访问
/hello:未登录时自动跳转至默认登录页,输入john/12345认证通过后可正常访问 - 访问
/bye:无论是否登录,都会返回403 Forbidden错误,无法调用该端点
内容的提问来源于stack exchange,提问作者Jeff Cook
相关产品推荐
相关产品推荐

