Integrating Spring Security with MyBatis for Database‑Based Login

This guide shows how to combine Spring Security and MyBatis to implement username‑password authentication backed by a MariaDB database, covering repository cloning, database setup, Maven execution, and a deep dive into the underlying authentication filter and provider classes with code examples.

Programmer DD
Programmer DD
Programmer DD
Integrating Spring Security with MyBatis for Database‑Based Login

GitHub Repository

https://github.com/ChinaSilence/any-spring-security/tree/master/security-login-db

Run the Application

Clone the project:

git clone https://github.com/ChinaSilence/any-spring-security.git

Enter the security-login-db directory.

Create a MySQL/MariaDB database named any and execute the provided user.sql script, which inserts two sample users ("anoy" and "admin").

Start the Spring Boot application with mvn spring-boot:run.

Open the web UI, register a new account if desired, and log in using the credentials stored in the database.

Spring Security Authentication Flow Diagram

Spring Security authentication flow
Spring Security authentication flow

AbstractAuthenticationProcessingFilter (core abstract class)

/**
 * Determines whether authentication is required and, if so, invokes
 * #attemptAuthentication(HttpServletRequest, HttpServletResponse).
 * The result can be:
 *   1) an Authentication object – the request is authenticated;
 *   2) an AuthenticationException – authentication failed;
 *   3) null – the subclass has handled the request (e.g., redirected).
 */
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    if (!requiresAuthentication(request, response)) {
        chain.doFilter(request, response);
        return;
    }
    try {
        Authentication authResult = attemptAuthentication(request, response);
        if (authResult == null) {
            return; // subclass indicates incomplete authentication
        }
        successfulAuthentication(request, response, chain, authResult);
    } catch (AuthenticationException failed) {
        unsuccessfulAuthentication(request, response, failed);
    }
}

UsernamePasswordAuthenticationFilter (concrete subclass)

public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    if (postOnly && !"POST".equals(request.getMethod())) {
        throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
    }
    String username = obtainUsername(request);
    String password = obtainPassword(request);
    if (username == null) username = "";
    if (password == null) password = "";
    username = username.trim();
    UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
    setDetails(request, authRequest);
    return this.getAuthenticationManager().authenticate(authRequest);
}

ProviderManager (AuthenticationManager implementation)

public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    Class<?> toTest = authentication.getClass();
    AuthenticationException lastException = null;
    Authentication result = null;
    for (AuthenticationProvider provider : getProviders()) {
        if (!provider.supports(toTest)) continue;
        try {
            result = provider.authenticate(authentication);
            if (result != null) break;
        } catch (AccountStatusException | InternalAuthenticationServiceException e) {
            lastException = e;
            break;
        } catch (AuthenticationException e) {
            lastException = e;
        }
    }
    if (result != null) return result;
    if (lastException == null) {
        throw new ProviderNotFoundException(messages.getMessage("ProviderManager.providerNotFound", new Object[] {toTest.getName()}, "No AuthenticationProvider found for {0}"));
    }
    throw lastException;
}

AbstractUserDetailsAuthenticationProvider (base class for DAO‑based providers)

public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication, "Only UsernamePasswordAuthenticationToken is supported");
    String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED" : authentication.getName();
    UserDetails user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
    preAuthenticationChecks.check(user);
    additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
    postAuthenticationChecks.check(user);
    if (!this.hideUserNotFoundExceptions) {
        // hide details of user‑not‑found for security reasons
    }
    return createSuccessAuthentication(user, authentication, user);
}

DaoAuthenticationProvider (concrete implementation)

protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
    try {
        UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
        if (loadedUser == null) {
            throw new InternalAuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation");
        }
        return loadedUser;
    } catch (UsernameNotFoundException notFound) {
        if (authentication.getCredentials() != null) {
            String presentedPassword = authentication.getCredentials().toString();
            this.passwordEncoder.isPasswordValid(this.userNotFoundEncodedPassword, presentedPassword, null);
        }
        throw notFound;
    } catch (Exception repositoryProblem) {
        throw new InternalAuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
    }
}

Custom UserDetailsService

The demo provides AnyUserDetailsService, which loads user data from the any_user table in the any database. It implements loadUserByUsername(String username) and returns a UserDetails instance containing username, password, and granted authorities (e.g., ROLE_USER, ROLE_ADMIN).

By following the steps above and understanding the filter‑provider chain, developers can adapt the configuration to other data sources, customize authentication logic, or extend Spring Security with additional filters.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavadatabaseSpring BootMyBatisAuthenticationspring-security
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.