Skip to main content
Advertisement

11.4 Authentication Flow and Practical Example

Authentication in Spring Security is achieved through the collaboration of several components. Here, we'll trace the full lifecycle of the most common Form Login (ID/PW) method.

1. Full Authentication Process (Mermaid)

sequenceDiagram
participant User as User(Client)
participant Filter as AuthenticationFilter
participant Manager as AuthenticationManager
participant Provider as AuthenticationProvider
participant Service as UserDetailsService
participant DB as Database

User->>Filter: 1. Login Request (username, password)
Filter->>Filter: 2. Create UsernamePasswordAuthenticationToken (unauthenticated)
Filter->>Manager: 3. Call authenticate(token)
Manager->>Provider: 4. Delegate authentication to a supporting Provider
Provider->>Service: 5. loadUserByUsername(username)
Service->>DB: 6. Query user info
DB-->>Service: Return User Entity
Service-->>Provider: 7. Return UserDetails object
Provider->>Provider: 8. Verify password (BCrypt comparison)
Provider-->>Manager: 9. Return authenticated Authentication object
Manager-->>Filter: 10. Authentication complete
Filter->>Filter: 11. Store info in SecurityContextHolder
Filter-->>User: 12. Success response/redirect

2. Roles of Key Components

  1. AuthenticationFilter: Intercepts the HTTP request, creates an unauthenticated Authentication object, and passes it to the Manager.
  2. AuthenticationManager: The main interface overseeing authentication. (Typically, the ProviderManager implementation is used.)
  3. AuthenticationProvider: Performs the actual business logic (e.g., ID/PW validation). Multiple providers can be registered to handle various authentication types (LDAP, DB, Social, etc.).
  4. UserDetailsService: Acts as the "data provider" that retrieves user information from a storage like a database.
  5. SecurityContextHolder: A storage area that keeps authenticated information accessible throughout the application.

3. Practical Example: Login API Implementation (JWT)

Following modern trends, here is a simple controller example that issues a JWT token after successful authentication.

LoginRequest DTO

public record LoginRequest(String email, String password) {}

AuthController

@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
public class AuthController {

private final AuthenticationManager authenticationManager;
private final TokenProvider tokenProvider;

@PostMapping("/login")
public ResponseEntity<String> login(@RequestBody LoginRequest request) {
// 1. Create an unauthenticated token
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(request.email(), request.password());

// 2. Start actual authentication (triggers Manager -> Provider -> Service flow)
// Throws exception if authentication fails
Authentication authentication = authenticationManager.authenticate(authenticationToken);

// 3. Store authentication info in context (optional but recommended)
SecurityContextHolder.getContext().setAuthentication(authentication);

// 4. Generate and return a JWT token based on authenticated info
String jwt = tokenProvider.createToken(authentication);
return ResponseEntity.ok(jwt);
}
}

4. Utilizing Authentication Info (@AuthenticationPrincipal)

Used when you want to directly access the logged-in user's information from a controller.

@GetMapping("/api/me")
public ResponseEntity<String> getMyInfo(@AuthenticationPrincipal UserDetails userDetails) {
return ResponseEntity.ok("Current User: " + userDetails.getUsername());
}

🎯 Key Points

  • Authentication goes through the stages of Filter -> Manager -> Provider -> Service.
  • The AuthenticationManager is the central role, while the Provider handles actual verification.
  • Once successful, user info is held in the SecurityContextHolder, making it accessible globally.
Advertisement