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

如何在Spring Boot中设计两套独立的身份认证与授权配置

Spring Boot 双路径分组认证授权实现方案

核心实现思路

使用Spring Security原生的多SecurityFilterChain机制,为两类路径分别配置独立的安全规则,避免链路互相干扰。

前置依赖

在pom.xml中引入安全starter:

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

1. 配置/api/**路径的安全规则

该路径优先级设置为最高,仅校验请求头的api-secret-key,无需身份认证:

1.1 自定义Api密钥校验过滤器

@Component
public class ApiSecretKeyFilter extends OncePerRequestFilter {
    // 可从配置文件注入合法密钥
    @Value("${api.secret-key}")
    private String validSecretKey;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String requestKey = request.getHeader("x-api-secret-key");
        // 密钥不匹配直接返回401
        if (!validSecretKey.equals(requestKey)) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("Invalid api secret key");
            return;
        }
        // 校验通过直接放行,无需设置认证上下文
        filterChain.doFilter(request, response);
    }
}

1.2 对应安全过滤器链配置

@Configuration
@Order(1) // 优先级高于admin路径配置
public class ApiSecurityConfig {
    @Autowired
    private ApiSecretKeyFilter apiSecretKeyFilter;

    @Bean
    public SecurityFilterChain apiSecurityFilterChain(HttpSecurity http) throws Exception {
        // 仅匹配/api/**路径的请求
        http.securityMatcher("/api/**")
                .csrf(AbstractHttpConfigurer::disable)
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                // 所有api路径请求全部放行,仅通过过滤器校验密钥
                .authorizeHttpRequests(auth -> auth.anyRequest().permitAll())
                // 把密钥校验过滤器加在用户名密码校验过滤器之前
                .addFilterBefore(apiSecretKeyFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }
}

2. 配置/admin/**路径的安全规则

该路径优先级次高,需用户名密码登录获取token后才可访问:

2.1 自定义JWT token校验过滤器

@Component
public class AdminTokenFilter extends OncePerRequestFilter {
    // 自行实现JWT工具类,包含token生成、校验、解析用户名功能
    @Autowired
    private JwtUtil jwtUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = request.getHeader("Authorization");
        // 登录接口直接放行
        if (request.getRequestURI().equals("/admin/login")) {
            filterChain.doFilter(request, response);
            return;
        }
        // token为空或校验不通过返回401
        if (token == null || !jwtUtil.validateToken(token)) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("Invalid or missing admin token");
            return;
        }
        // 校验通过后将用户信息存入安全上下文
        String username = jwtUtil.getUsernameFromToken(token);
        UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(username, null, Collections.emptyList());
        SecurityContextHolder.getContext().setAuthentication(auth);
        filterChain.doFilter(request, response);
    }
}

2.2 登录接口实现

@RestController
@RequestMapping("/admin")
public class AdminLoginController {
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private JwtUtil jwtUtil;

    @PostMapping("/login")
    public String login(@RequestBody LoginRequest request) {
        // 调用自定义UserDetailService做身份认证
        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())
        );
        SecurityContextHolder.getContext().setAuthentication(authentication);
        // 认证通过生成token返回
        return jwtUtil.generateToken(authentication.getName());
    }
}

2.3 对应安全过滤器链配置

@Configuration
@Order(2)
public class AdminSecurityConfig {
    @Autowired
    private AdminTokenFilter adminTokenFilter;
    @Autowired
    private CustomUserDetailService customUserDetailService;

    @Bean
    public SecurityFilterChain adminSecurityFilterChain(HttpSecurity http) throws Exception {
        http.securityMatcher("/admin/**")
                .csrf(AbstractHttpConfigurer::disable)
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(auth -> auth
                        // 登录接口放行
                        .requestMatchers("/admin/login").permitAll()
                        // 其他admin接口需要认证
                        .anyRequest().authenticated()
                )
                .addFilterBefore(adminTokenFilter, UsernamePasswordAuthenticationFilter.class)
                // 注册自定义UserDetailService和密码加密器
                .userDetailsService(customUserDetailService)
                .authenticationProvider(authenticationProvider());
        return http.build();
    }

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

    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(customUserDetailService);
        provider.setPasswordEncoder(passwordEncoder());
        return provider;
    }

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

关键注意事项

  • 每个SecurityFilterChain必须显式调用securityMatcher绑定对应路径,否则会默认匹配所有请求,导致高优先级链路拦截全部流量
  • 优先级数值越小优先级越高,需保证/api链路的优先级高于/admin链路
  • 两类路径的过滤器互相独立,不会交叉生效,无需额外做路径排除逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 21:15:04