Spring 5 Web应用集成Waffle实现Windows认证及LDAP查询问题
Hey there! Let's walk through how you can tap into Waffle's authentication flow to grab the Windows username and run your LDAP queries. I'll break down the key spots to add your custom code, based on the configuration you've shared.
First, Understand Waffle's Authentication Flow
When a user logs in with Windows credentials, Waffle's NegotiateSecurityFilter handles the handshake, validates the credentials, and generates a WindowsAuthenticationToken. This token contains a WindowsPrincipal that holds all the user's Windows identity details—including the username you need.
Option 1: Use an Authentication Success Handler (Cleanest Approach)
This is the most straightforward way to run custom logic right after successful authentication. You can create a custom AuthenticationSuccessHandler that grabs the username and executes your LDAP query.
Step 1: Create the Custom Success Handler
import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import waffle.spring.WindowsAuthenticationToken; import waffle.windows.auth.WindowsPrincipal; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class CustomAuthSuccessHandler implements AuthenticationSuccessHandler { // Inject your LDAP service here if you have one // @Autowired // private LdapUserService ldapUserService; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { // Check if we're dealing with a Waffle Windows authentication token if (authentication instanceof WindowsAuthenticationToken) { WindowsAuthenticationToken waffleToken = (WindowsAuthenticationToken) authentication; WindowsPrincipal windowsPrincipal = (WindowsPrincipal) waffleToken.getPrincipal(); // Get the full Windows username (format: DOMAIN\\username) String fullWindowsUsername = windowsPrincipal.getUsername(); // If you just need the username without the domain, split it String username = fullWindowsUsername.split("\\\\")[1]; // Run your LDAP query here! // Example: LdapUserDetails userDetails = ldapUserService.fetchUserByUsername(username); // Store the LDAP results in the session or SecurityContext for later use // request.getSession().setAttribute("ldapUserDetails", userDetails); } // Redirect to your app's home page or send a success response response.sendRedirect("/dashboard"); } }
Step 2: Wire It Into Your Security Config
For Java Config:
Update your configure(HttpSecurity http) method to attach the success handler:
@Override protected void configure(final HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .addFilterBefore(this.securityFilter, BasicAuthenticationFilter.class) .httpBasic() .authenticationEntryPoint(this.authenticationEntryPoint) .and() .authenticationProvider(windowsAuthenticationProvider) .formLogin() .successHandler(new CustomAuthSuccessHandler()); // Add this line }
For XML Config:
Define the handler bean and link it to the form login:
<beans:bean id="customAuthSuccessHandler" class="sunrise.crm.webapp.common.security.CustomAuthSuccessHandler" /> <http use-expressions="true"> <intercept-url pattern="/**" access="isAuthenticated()" /> <custom-filter ref="waffleNegotiateSecurityFilter" position="BASIC_AUTH_FILTER" /> <form-login authentication-success-handler-ref="customAuthSuccessHandler" /> <http-basic /> </http>
Option 2: Extend WindowsAuthenticationProvider
If you want to run logic during the authentication process itself (before the user is fully authenticated), you can extend Waffle's WindowsAuthenticationProvider:
import org.springframework.security.core.Authentication; import waffle.spring.WindowsAuthenticationProvider; import waffle.windows.auth.IWindowsAuthProvider; import waffle.spring.WindowsAuthenticationToken; public class CustomWindowsAuthProvider extends WindowsAuthenticationProvider { // Inject your LDAP service here // @Autowired // private LdapUserService ldapUserService; public CustomWindowsAuthProvider(IWindowsAuthProvider authProvider) { super.setAuthProvider(authProvider); } @Override public Authentication authenticate(Authentication authentication) { // Let Waffle handle the core Windows authentication first Authentication authenticatedToken = super.authenticate(authentication); if (authenticatedToken.isAuthenticated()) { WindowsAuthenticationToken waffleToken = (WindowsAuthenticationToken) authenticatedToken; String fullUsername = waffleToken.getWindowsIdentity().getFqn(); String username = fullUsername.split("\\\\")[1]; // Execute your LDAP query here // Example: LdapUserDetails userDetails = ldapUserService.fetchUserByUsername(username); // You can attach LDAP details to the authentication token if needed // waffleToken.setDetails(userDetails); } return authenticatedToken; } }
Update Your Provider Bean
Java Config:
Replace your existing windowsAuthenticationProvider bean:
@Bean @Autowired public WindowsAuthenticationProvider windowsAuthenticationProvider(final WindowsAuthProviderImpl windowsAuthProvider) { return new CustomWindowsAuthProvider(windowsAuthProvider); }
XML Config:
Update your custom provider definition:
<beans:bean id="customAuthenticationProvider" class="sunrise.crm.webapp.common.security.CustomWindowsAuthProvider"> <beans:constructor-arg ref="waffleWindowsAuthProvider" /> </beans:bean>
Quick Notes to Keep in Mind
- Username Format: Waffle returns usernames in
DOMAIN\\usernameformat—make sure to split it if you only need the username part. - Dependency Compatibility: Ensure your Waffle version is compatible with Spring 5 (Waffle 2.x and above work well with Spring 5).
- LDAP Service: Wrap your LDAP query logic in a dedicated service class, then inject it into your success handler or provider for clean code separation.
内容的提问来源于stack exchange,提问作者Abhishake Kumar

