You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用SecurityFilterChain配置Spring Security端点权限:仅/hello需授权

Spring Boot 2.7.1 基于SecurityFilterChain的权限控制实现方案

需求回顾

  • /hello端点:需授权访问,未登录时自动跳转至Spring Security默认登录页
  • /bye端点:禁止所有访问,直接返回401/403错误,无法调用

现有代码问题分析

  1. 权限规则缺失:当前配置仅限制了/hello需认证,但/bye默认允许匿名访问,不符合需求
  2. 自定义认证逻辑未生效:MyAuthenticationProvider未被Spring Security加载,无法替代默认认证流程
  3. 密码验证不规范: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),避免认证后因权限不足导致访问异常

测试效果

  1. 访问/hello:未登录时自动跳转至默认登录页,输入john/12345认证通过后可正常访问
  2. 访问/bye:无论是否登录,都会返回403 Forbidden错误,无法调用该端点

内容的提问来源于stack exchange,提问作者Jeff Cook

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 19:52:41