FC
FACADE
CODE
Lesson 20 of 28
FC
FACADE
CODE

Learn Spring Security

Contents

01. Bootstrap The Application
1. Introduction
2. Install Spring Security
3. Enable Basic Auth
4. Authentication with AppUser
5. Password Encoder
02. Web Layer Security - RBAC
6. Permit Public APIs
7. Role Based Authorization
8. Disable CSRF
9. Current Authenticated User
03. Web Layer Security - PBAC
10. Permission Based Authorization
11. Define Permissions
12. Assign Permissions
13. Remove Role Based Access
04. Service Layer Security
14. PreAuthorize
15. PostAuthorize
16. Authorize Using Spring Beans
05. Domain Object Instance Security
17. Domain Object Instance Security
18. PermissionEvaluator Interface
19. PermissionEvaluator Strategy
20. DB Backed UserDetailsService
06. Token Based Authentication
21. Basic Authentication Revisited
22. Generate Token
23. Persist Token
24. Verify Token
25. Invalidate Token
07. Token Based Authentication and Authorization
26. JSON Web Token
27. Generate JWT
28. Verify JWT

Database Backed UserDetailsService

Remember we are using InMemoryUserDetailsManager, the default non-persistant implementation of UserDetailsService provided by Spring Security. It is mainly intended for testing and demonstration purposes. Any change in the user details in the database requires us to restart the application. We need an implementation backed by database for production.

UserDetailsService

UserDetailsService is used by DaoAuthenticationProvider for retrieving a username, password, and other attributes for authenticating with a username and password. We can define custom authentication by exposing a custom UserDetailsService as a bean.

Let's implement it using our DbUserDetailsService bean by overriding the loadUserByUsername() method.


@Service
public class DbUserDetailsService implements UserDetailsService {
    // Other details omitted for brevity

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        AppUser appUser = appUserRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException(String.format("User %s not found", username)));

        return User.builder()
                .username(appUser.getUsername())
                .password(appUser.getPassword())
                .authorities(this.getPermissions(appUser.getRoles()))
                .build();
    }
}

Here we are using AppUserRepository to find the user by username from the database. And then we are returning the UserDetails object mapped from the AppUser object.

Once we remove the InMemoryUserDetailsManager bean from SecurityBean configuration, DaoAuthenticationProvider will automatically use the DbUserDetailsService component to load the user by username for authentication. And we can also remove the existing loadAllUserDetails() method as it is no longer required.

Note

Please note there is no change in the security restrictions we have applied so far as we have just swapped the UserDetailsService implementation from non-persistant datastore to persistant datastore.