Reputation: 71
I'm following the tutorial in this video: https://www.youtube.com/watch?v=X80nJ5T7YpE&list=PLqq-6Pq4lTTYTEooakHchTGglSvkZAjnE&index=12
My code is at the state of the 7:30 mark. For whatever reason, I can't seem to get the SecurityConfigurer.java
Class to recognize my custom UserDetailsService class called MyUserDetailsService.java
.
The expected behavior is that when I go to the /hello endpoint I've specified in HelloResource.Java
class, a login page should be generated. I should be able to login to the webpage with the loadUserByUsername
method's hard-coded return User value with the username and password of "foo".
No matter what change I make though, it always seems that the loadUserByUsername
method is not called (I've proven this with breakpoints/print statements). This leads me to believe that there might be some component scanning problem, vut I have yet to see anything work!
I've already tried the solutions at these links: One, Two, Three, plus a few more. Here are my relevant files:
JWTMain.java
package com.JWTTest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan("{com.JWTTest}")
public class JwtMain {
public static void main(String[] args) {
SpringApplication.run(JwtMain.class, args);
}
}
HelloResource.java
package com.JWTTest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloResource {
@RequestMapping("/hello")
public String HelloString(){
return "Hello";
}
}
MyUserDetailsService.java
package com.JWTTest;
import org.jvnet.hk2.annotations.Service;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import java.util.ArrayList;
@Service
public class MyUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return new User("foo", "foo", true, true, true, true, new ArrayList<>());
}
}
SecurityConfigurer.java
package com.JWTTest;
import org.apache.catalina.security.SecurityConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@ComponentScan(basePackageClasses = MyUserDetailsService.class)
@EnableWebSecurity(debug = true)
@Import(value = {SecurityConfig.class})
public class SecurityConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
private MyUserDetailsService myUserDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(myUserDetailsService);
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/spring_security
spring.jpa.properties.hibernate.default_schema=users
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
build.gradle
plugins {
id 'org.springframework.boot' version '2.2.1.RELEASE'
id 'io.spring.dependency-management' version '1.0.8.RELEASE'
id 'java'
}
group = 'com.JWTTest'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-hateoas'
implementation 'org.springframework.boot:spring-boot-starter-jersey'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-web-services'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.data:spring-data-rest-hal-browser'
implementation 'org.springframework.session:spring-session-core'
implementation 'org.springframework.boot:spring-boot-starter-security'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: '2.2.1.RELEASE'
compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.15'
compileOnly 'org.projectlombok:lombok'
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-thymeleaf")
compile("org.springframework.boot:spring-boot-devtools")
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation 'io.projectreactor:reactor-test'
implementation 'org.springframework.boot:spring-boot-starter-cache'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
test {
useJUnitPlatform()
}
Besides that I can't make heads or tails of what's going on. Let me know, thanks.
Upvotes: 2
Views: 1652
Reputation: 71
The solution:
@SpringBootApplication
@ComponentScan
should be in the main method. As long as @EnableWebSecurity is in the SecurityConfigurer class, Springboot is aware that one is trying to override the Springboot provided Security class. The problem with my main method was Springboot wasn't scanning my classes properly.
I also learned that one could exclude the Springboot provided Security class by putting this annotation above the main class:
@SpringBootApplication(exclude = { SecurityAutoConfiguration.class })
Upvotes: 0
Reputation: 1648
In MyUserDetailsService.java
you're importing org.jvnet.hk2.annotations.Service
while the correct one is org.springframework.stereotype.Service
.
Upvotes: 1