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

基于Spring Security实现多认证方式及请求执行流程咨询

Hey there! Let's break this down clearly for you since you already have a solid foundation in Spring Security filters and AuthenticationManager—great start!

Spring Security 请求执行顺序 & 双认证实现指南

一、请求与过滤器、认证管理器的交互顺序

Your hunch is totally correct, but let's flesh out the full flow to eliminate any ambiguity:

  • When a request hits your app, it first enters the Spring Security Filter Chain. Filters here run in a fixed, predefined order (this order matters a lot—each filter handles specific security tasks like CSRF protection, request caching, or authentication processing).
  • When the request reaches an authentication-focused filter (like UsernamePasswordAuthenticationFilter for username/password logins, or a custom filter you build for JWT), that filter constructs an Authentication object (e.g., UsernamePasswordAuthenticationToken for credentials, or a custom JwtAuthenticationToken for tokens). It then calls AuthenticationManager.authenticate() to kick off the actual authentication logic.
  • The AuthenticationManager itself delegates to the right AuthenticationProvider (e.g., DaoAuthenticationProvider for username/password checks, your custom JwtAuthenticationProvider for token validation). The provider does the heavy lifting: checking database credentials, verifying JWT signatures, fetching user details, etc.
  • If authentication succeeds, the filter stores the validated Authentication object in SecurityContextHolder—so subsequent filters and your business code can access the current user's identity. If it fails, Spring Security triggers its built-in error handling flow.

二、实现JWT + 用户名密码双认证(结合security.xml)

Here's a practical breakdown of how to configure both auth methods in your security.xml and supporting code:

1. Configure Username/Password Authentication

First, set up the filter that handles login requests and ties it to your AuthenticationManager:

<bean id="usernamePasswordAuthFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
    <!-- Link to your central AuthenticationManager -->
    <property name="authenticationManager" ref="authenticationManager"/>
    <!-- Custom handler for successful login (e.g., return a JWT token) -->
    <property name="authenticationSuccessHandler" ref="customAuthSuccessHandler"/>
    <!-- Custom handler for failed login (e.g., return error details) -->
    <property name="authenticationFailureHandler" ref="customAuthFailureHandler"/>
</bean>

Then configure the provider that validates username/password pairs using your user data source:

<bean id="daoAuthProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
    <!-- Your custom UserDetailsService that fetches user data from DB -->
    <property name="userDetailsService" ref="customUserDetailsService"/>
    <!-- Password encoder (always use a strong one like BCrypt) -->
    <property name="passwordEncoder" ref="bcryptPasswordEncoder"/>
</bean>

2. Configure JWT Authentication Filter

You'll need a custom filter to intercept protected requests, extract JWT tokens from headers, and trigger authentication:

// Example custom JWT filter (Java code, to be wired in XML)
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    private AuthenticationManager authenticationManager;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // Extract token from Authorization header (format: Bearer <token>)
        String token = extractToken(request);
        if (token != null) {
            // Create an auth request object for JWT
            Authentication authRequest = new JwtAuthenticationToken(token);
            // Let AuthenticationManager handle validation
            Authentication authResult = authenticationManager.authenticate(authRequest);
            // Store valid auth in security context for downstream use
            SecurityContextHolder.getContext().setAuthentication(authResult);
        }
        // Pass request to next filter in the chain
        filterChain.doFilter(request, response);
    }

    private String extractToken(HttpServletRequest request) {
        String authHeader = request.getHeader("Authorization");
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            return authHeader.substring(7);
        }
        return null;
    }
}

Wire this filter into your security.xml, making sure it runs before the username/password filter (so protected requests are checked for JWT first):

<bean id="jwtAuthFilter" class="com.yourpackage.JwtAuthenticationFilter">
    <property name="authenticationManager" ref="authenticationManager"/>
</bean>

3. Wire AuthenticationManager with Both Providers

The AuthenticationManager (typically ProviderManager) will route auth requests to the correct provider based on the Authentication object type:

<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
    <property name="providers">
        <list>
            <ref bean="daoAuthProvider"/> <!-- Handles username/password -->
            <ref bean="jwtAuthProvider"/> <!-- Your custom JWT provider -->
        </list>
    </property>
</bean>

You'll need to implement jwtAuthProvider yourself: it should implement AuthenticationProvider, override supports() to recognize JwtAuthenticationToken, and handle token parsing, signature validation, and user lookup in authenticate().

4. Set Up Filter Chain Order & Access Rules

In your <http> config, define the filter order and which endpoints are accessible:

<http auto-config="false" use-expressions="true">
    <!-- Place JWT filter before the default form login filter -->
    <custom-filter ref="jwtAuthFilter" before="FORM_LOGIN_FILTER"/>
    <!-- Replace default form login filter with your custom one -->
    <custom-filter ref="usernamePasswordAuthFilter" position="FORM_LOGIN_FILTER"/>
    
    <!-- Allow anonymous access to login endpoint (so users can get JWTs) -->
    <intercept-url pattern="/login" access="permitAll()"/>
    <!-- Require authentication for all other endpoints -->
    <intercept-url pattern="/**" access="isAuthenticated()"/>
    
    <!-- Disable CSRF if using JWT (safe for stateless APIs) -->
    <csrf disabled="true"/>
</http>

三、Key Takeaways

  • The filter chain is Spring Security's backbone—requests flow through filters in order, and auth filters trigger the AuthenticationManager to handle validation.
  • Dual authentication works by using distinct Authentication objects and matching AuthenticationProviders; the AuthenticationManager automatically routes requests to the right provider.
  • Keep your login endpoint open to anonymous users so they can retrieve JWT tokens, then use those tokens to access protected resources.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 08:58:11