If you use the JDBC-based authentication scheme described earlier, you must follow certain specifications, such as field name name restrictions, and so on. So if we need full customization, we can use a direct Spring Data Repository.

Craig Walls gives an example of how to customize the account permissions system.

1 Define the account entity class

@Entity @Data @NoArgsConstructor(access = AccessLevel.PRIVATE, force = true) @RequiredArgsConstructor public class User implements UserDetails { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private final String username; private final String password; private final String fullname; private final String street; private final String city; private final String state; private final String zip; private final String phoneNumber; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")); } @Override public String getPassword() { return null; } @Override public String getUsername() { return null; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; }}Copy the code

In addition to defining some basic account properties, the User class also implements Spring Security’s UserDetails interface. This interface defines a number of permission-related methods.

The method name instructions
getAuthorities Returns the set of permissions granted to this account
isAccountNonExpired Whether the account has not expired
isAccountNonLocked Whether the account is not locked
isCredentialsNonExpired Whether the account credentials have not expired
isEnabled Is the account available

In the sample code, all of these methods return TRUE, allowing the account to log in.

2 Account Repository interface

public interface UserRepository extends CrudRepository<User,Long> {

    User findByUsername(String username);
}
Copy the code

Spring Data JPA automatically generates an implementation class for the Repository interface for the account at runtime. The advantage of this approach is that you don’t need to write code.

3 Account Service interface

Spring Security itself defines the UserDetailsService interface with the following code:

public interface UserDetailsService {

    UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
Copy the code

The Service interface defines a method to get an account based on its name. If you can’t find the corresponding account, will be thrown UsernameNotFoundException anomalies.

UserDetailsService is the interface defined by Spring Security.

Define the implementation class of UserDetailsService:

@Service public class UserRepositoryUserDetailsService implements UserDetailsService { private UserRepository userRepository; @Autowired public UserRepositoryUserDetailsService(UserRepository userRepository) { this.userRepository = userRepository; } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username); if (user ! = null) { return user; } else { throw new UsernameNotFoundException("User '" + username + "' not found"); }}}Copy the code

The implementation class of UserDetailsService injects UserRepository as a constructor. The findByUsername method of UserRepository is then used to query the account object in the loadUserByUsername method. The implementation class of UserDetailsService uses the @Service annotation so that when the Spring application starts, it initializes it as a bean.

Next, you need to bind the UserDetailsService service to Spring Security. In the SecurityConfig class, inject and bind the UserDetailsService service:Copy the code
  @Autowired
  UserDetailsService userDetailsService;

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}

Copy the code

As with JDBC, you can configure the cipher encoder so that the passwords stored in the database are ciphertext.

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

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(userDetailsService)
        .passwordEncoder(encoder());
}
Copy the code

First define a method that returns a PasswordEncoder object, and then call the PasswordEncoder () method, which takes the PasswordEncoder object as an input, So AuthenticationManagerBuilder object on the assembly code encoder.

Because the Encoder () method defines the @bean annotation, all calls to the Encoder () method are intercepted by Spring, and the Spring framework returns an instance of the PasswordEncoder Bean in the application context.


With this approach, we can implement a custom Spring Security permission system.