Problem in Spring Security
unknown
java
7 months ago
6.1 kB
65
Indexable
// trying to implement basic username-password authentication in spring.. no JWT yet
// application flow, as per my understanding: - FilterChain => AuthenticaionManager (ProviderManager) => accesses AuthenticationProvider (in my case, its DaoAuthenticationProvider) => accesses UserDetailsService (in this case, JdbcUserDetailsService) => accesses DataSource to connect to DB
// conclusion reached by me: Create custom UserDetailsService, create custom User model; tell spring security to use these custom ones instead of its default values
// 1. Created CustomUserDetailsService and its implemmentation
// CustomUserDetailsService.java
@Service
public interface CustomUserDetailsService extends UserDetailsService{
public String create(String username, String password, String email);
}
// CustomUserDetailsServiceImpl.java
@Component
public class CustomUserDetailsService implements CustomUserDetailsService {
@Autowired
private CustomUserRepository userRepo;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return userRepo.findByUsername(username);
}
public String create(String username, String password, String email) {
// Encodes the password and creates a new User object
CustomUser u = new CustomUser(username, new BCryptPasswordEncoder().encode(password), email);
u.setRole(List.of("USER"));
// Saves the new user to the database
userRepo.save(u);
return "Create Successfully !";
}
}
// CustomUserRepository.java
public interface CustomUserRepository extends JpaRepository<CustomUser, Long> {
public UserDetails findByUsername(String username);
}
// 2. Created Custom User model
// CustomUser.java
@Entity
public class CustomUser implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String username;
private String email;
private String password;
private List<String> role;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return role.stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role))
.collect(Collectors.toList());
}
@Override
public String getPassword() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getUsername() {
// TODO Auto-generated method stub
return null;
}
public void setPassword(String password) {
this.password = password;
}
public List<String> getRole() {
return role;
}
public void setRole(List<String> role) {
this.role = role;
}
public CustomUser() {
super();
// TODO Auto-generated constructor stub
}
public CustomUser(long id, String username, String email) {
super();
this.id = id;
this.username = username;
this.email = email;
}
public CustomUser(String username, String email, String password) {
super();
this.username = username;
this.email = email;
this.password = password;
}
}
// 3. Telling Spring Security to use these custom objects instead of its own default config
// WebSecurityConfig.java
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Autowired
private CustomUserService customUserService;
@Value("${spring.datasource.driver-class-name}")
public String databaseDriverClassName;
@Value("${spring.datasource.url}")
public String databaseUrlName;
@Value("${spring.datasource.username}")
public String databaseUsername;
@Value("${spring.datasource.password}")
public String databasePassword;
// 1. custom security filter chain for authorization and authentication paths
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
return httpSecurity
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/unauth/*").permitAll()
.requestMatchers("/login/").permitAll()
.anyRequest().denyAll()
)
.httpBasic(Customizer.withDefaults())
.build();
}
// 2. setup datasource to connect to database --> This is causing problem (the circular dependency error I mentioned)
// @Bean
// public DriverManagerDataSource dataSource() {
// DriverManagerDataSource dataSource = new DriverManagerDataSource();
// dataSource.setDriverClassName(databaseDriverClassName);
// dataSource.setUrl(databaseUrlName);
// dataSource.setUsername(databaseUsername);
// dataSource.setPassword(databasePassword);
// System.out.println("datasource initialized");
// return dataSource;
// }
}
// Here is complete error log
// Description:
// The dependencies of some of the beans in the application context form a cycle:
// entityManagerFactory defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]
// ┌─────┐
// | dataSourceScriptDatabaseInitializer defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]
// ↑ ↓
// | webSecurityConfig (field private com.sample.springsecurity.service.CustomUserDetailsService com.sample.springsecurity.config.WebSecurityConfig.customUserDetailsService)
// ↑ ↓
// | customUserDetailsServiceImpl (field private com.sample.springsecurity.repository.CustomUserRepository com.sample.springsecurity.serviceImpl.CustomUserDetailsServiceImpl.userRepo)
// ↑ ↓
// | customUserRepository defined in com.sample.springsecurity.repository.CustomUserRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration
// ↑ ↓
// | jpaSharedEM_entityManagerFactory
// └─────┘
// Action:
// Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.
// What I cannot understand -> Where exactly is spring injecting this datasource bean? from what I have understood, it should only be injecting it inside the
Editor is loading...
Leave a Comment