Custom Login in Spring Boot 3 Without WebSecurityConfigurerAdapter

Jacky - Oct 9 '23 - - Dev Community

When I first set out to migrate my Spring Boot application from version 2 to 3, I was excited about all the new features and improvements. However, I soon hit a roadblock: my custom authentication logic built on older Spring Security libraries no longer worked. We don't see WebSecurityConfigurerAdapter in Spring Boot 3. Spring Security's APIs had changed significantly. This main reason a wirte this article.

Custom login pages allow us to provide a tailored authentication experience for users of our Spring Boot applications. The default login form provided by Spring Security is useful, but often we need more flexibility to match the rest of our UI.

We'll see how to:

  • Create a login template with username and password fields
  • Post the form to a custom controller endpoint
  • Authenticate against user accounts in the database
  • Configure Spring Security for custom authentication

The completed demo app includes these key features:

  • Custom /login page for handling authentication
  • Database-backed user accounts with encoded passwords

Let's dive in and see how to wire up these pieces!

Configuring Spring Security

Now we need to wire up Spring Security to use our custom authentication logic. This involves:

  • Loading user details from the database
  • Encoding passwords with BCrypt
  • Registering our authentication provider
  • We can accomplish the configuration in a SpringSecurityConfig:
@Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(authz -> authz
            .requestMatchers("/login", "/error").permitAll()
            .anyRequest().authenticated()
        );

        http.formLogin(authz -> authz
            .loginPage("/login").permitAll()
        );

        http.logout(authz -> authz
            .deleteCookies("JSESSIONID")
            .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
        );

        return http.build();
    }

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

    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(customUserDetailsService);
        authenticationProvider.setPasswordEncoder(passwordEncoder());
        return authenticationProvider;
    }
Enter fullscreen mode Exit fullscreen mode

This ties everything together - let's look at the key pieces next.

The UserDetailsService implementation can query this table to load credentials:

@Service
public class CustomUserDetailsService implements UserDetailsService {

    private final UserRepository userRepository;

    CustomUserDetailsService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User admin = userRepository.findByUsername(username).orElseThrow(() -> new UsernameNotFoundException("Cannot found user"));
        List<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority("ROLE_" + admin.getRole()));
        AuthUser authUser = new AuthUser(username, admin.getPassword(), authorities);
        authUser.setId(admin.getId().toString());
        authUser.setDisplayName(admin.getFirstName());

        return authUser;
    }
}
Enter fullscreen mode Exit fullscreen mode

On startup, we also insert a test user with encoded password via BulkAdminUser.java.

Conclusion

In this article we implemented a custom login page in Spring Boot 3 from start to finish. The key takeaways include:

  • How to post login forms to your own controller
  • Authenticating with a database-backed user store
  • Configuring custom authentication in Spring Security

The full code for this demo is available on GitHub - check it out to see these concepts in action. You can also build on this foundation to craft targeted login experiences for your Spring applications.

Demo: https://github.com/jackynote/springboot3-example-login-spring-security

There's a lot more we could do, like adding remember-me, 2FA, and registration flows. But this covers the core and provides a great starting point for your custom auth needs. Let me know in the comments if you have any other questions!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .