Skip to main content
PreparationZone Logo
PrepZone

Form Login, HTTP Basic, and Method Security

Stateful sessions versus stateless Basic auth, in-memory and database users, and @PreAuthorize / @PostAuthorize.

Pass checkpoint below

Why this matters

  • Interviews split authentication into stateful (session) and stateless (Basic or JWT). Mixing them — Basic plus a session cookie, or form login with CSRF disabled — is a common production bug.
  • "Where do users live?" has two textbook answers: an in-memory UserDetailsService for demos, and a database-backed one for BookStore.
  • URL rules are not enough once a service method is called from several controllers. @PreAuthorize and @PostAuthorize are the second line.

Form login

L1 · Fresher

The browser posts username and password to /login. Spring creates an authenticated SecurityContext and a session cookie.

HTTP Basic

L2 · Intermediate

Each request carries Authorization: Basic base64(user:password). No login page, no session, credentials on the wire every time.

User stores

L3 · Advanced

InMemoryUserDetailsManager holds users in the JVM. UserDetailsService backed by JPA loads them from PostgreSQL and checks a BCrypt hash.

Method security

L4 · Expert

@PreAuthorize runs before the method. @PostAuthorize can filter the return value. Both need @EnableMethodSecurity and a Spring proxy.

In-memory users

Fine for a local demo and for tests. The users disappear on restart and cannot be shared across pods.

Java
// learn:fragment
@Configuration
@EnableWebSecurity
public class DemoSecurityConfig {

    @Bean
    public UserDetailsService users(PasswordEncoder encoder) {
        UserDetails reader = User.builder()
            .username("reader@bookstore.test")
            .password(encoder.encode("reader-secret"))
            .roles("READER")
            .build();
        UserDetails admin = User.builder()
            .username("admin@bookstore.test")
            .password(encoder.encode("admin-secret"))
            .roles("ADMIN")
            .build();
        return new InMemoryUserDetailsManager(reader, admin);
    }

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

roles("ADMIN") stores the authority ROLE_ADMIN. hasRole("ADMIN") looks for that prefix. hasAuthority("ROLE_ADMIN") is the same check spelled out.

Do not call encoder.encode on every authentication. Encode when you build the user, and store the hash.

The rest of this guide is part of Pro

Free covers every fresher guide in full. Pro unlocks Senior, Staff and Architect guides across every track.

Still to come · 4 sections

  • Database users
  • Form login — stateful
  • HTTP Basic — stateless
  • Method security

Test yourself

Answer these before moving on — recall is what makes it stick.