基于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!
一、请求与过滤器、认证管理器的交互顺序
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
UsernamePasswordAuthenticationFilterfor username/password logins, or a custom filter you build for JWT), that filter constructs anAuthenticationobject (e.g.,UsernamePasswordAuthenticationTokenfor credentials, or a customJwtAuthenticationTokenfor tokens). It then callsAuthenticationManager.authenticate()to kick off the actual authentication logic. - The
AuthenticationManageritself delegates to the rightAuthenticationProvider(e.g.,DaoAuthenticationProviderfor username/password checks, your customJwtAuthenticationProviderfor 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
Authenticationobject inSecurityContextHolder—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
AuthenticationManagerto handle validation. - Dual authentication works by using distinct
Authenticationobjects and matchingAuthenticationProviders; theAuthenticationManagerautomatically 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

