I'm new to spring so not fully aware of how the UserDetailsService works.
What I would like is for my login form to act the same way my signup form does. However, instead, when sending a post request using login details the UserDetailsService class seems to execute first. Can someone explain how the UserDetailsService works (i.e. when its called) and how I can change my security config to execute whats in my controller POST method for login (as it does for signup).
Controller:
@Controller
public class controller{
@RequestMapping(value = "/signup", method = RequestMethod.POST)
public String registration(@ModelAttribute("userForm") final User userForm, final BindingResult bindingResult) {
LOG.debug("Signing up with user: {}", userForm);
signUpValidationService.validate(userForm, bindingResult);
if (bindingResult.hasErrors()) {
return "login/Signup";
}
userService.saveUser(userForm);
userService.autologin(userForm.getEmail(), userForm.getPassword());
return "about/Home";
}
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(@ModelAttribute("userForm") final User userForm, final BindingResult bindingResult) {
LOG.debug("Logging in with user: {}", userForm);
loginValidationService.validate(userForm, bindingResult);
if (bindingResult.hasErrors()) {
return "login/Login";
}
userService.autologin(userForm.getEmail(), userForm.getPassword());
LOG.debug("Successfully logged in with user: {}", userForm.getFirstName());
return "about/Home";
}
}
My security config:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig
extends WebSecurityConfigurerAdapter {
/**
* {@inheritDoc}
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/resources/**", "/signup", "/", "/home", "/about")
.permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.successHandler(successHandler())
.permitAll()
.and()
.logout().deleteCookies("JSESSIONID")
.logoutUrl("/logout")
.logoutSuccessUrl("/home")
.permitAll()
.and()
.rememberMe().key("uniqueAndSecret").tokenValiditySeconds(86400)
.and()
.sessionManagement()
.sessionFixation().migrateSession()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.invalidSessionUrl("/invalid_session")
.maximumSessions(2)
.expiredUrl("/expired_session");
}
/**
* User login validation configuration.
*
* @param auth
* {@link AuthenticationManagerBuilder}
* @param userDetailsService
* {@link UserDetailsService}
* @throws Exception
* {@link Exception}
*/
@Autowired
public void configureGlobal(final AuthenticationManagerBuilder auth, final UserDetailsService userDetailsService)
throws
Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(new BCryptPasswordEncoder());
}
/**
* Handles login success configuration policy.
*
* @return {@link AuthenticationSuccessHandler}
*/
private final AuthenticationSuccessHandler successHandler() {
return new UrlAuthenticationSuccessHandler();
}
/**
* Sets security evaluation context.
*
* @return {@link SecurityEvaluationContextExtension}
*/
@Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}
}
Spring security auto detect your yourOwnuserDetailsService wich implemented UserDetailsService and when user enters their username and password into a login screen and clicks a login button. The entered information is placed into an object called Authentication which is passed to the AuthenticationManager’s authenticate method. this method will loop through all AuthenticationProviders that are configured and calls their authenticate method, passing in the Authentication object. Each AuthenticationProvider will calls its configured UserDetailsService’s loadUserByUserName method.
you don't need to call it explicitly, spring security will take care of it if you need if you need catch Spring Security login form before Spring security catch it, here is details
You can do this using regular Spring Security functionality. The steps are:
Implement a custom WebAuthenticationDetailsSource and WebAuthenticationDetails. The WebAuthenticationDetails will capture the extra form fields that you want to validate.
Note: In Spring 3.0 you'll need to use a BeanPostProcessor to configure the WebAuthenticationDetailsSource into the UsernamePasswordAuthenticationFilter. In Spring 3.1 you can do this directly in the namespace config.
Implement a custom AuthenticationProvider and in authenticate() check the WebAuthenticationDetails, throwing a AuthenticationException if validation fails. In your login page check for this exception.
Alternatively, you can create a Filter that does your validation and add it before the Spring Security filter.
Also if you want validate parameters then you can check it with extends UsernamePasswordAuthenticationFilter
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
//your logic
return super.attemptAuthentication(request, response);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With