Reputation: 582
I've been following this tutorial to get JWT authentication in Spring, but for some reason, the filters are not working for me. I have downloaded the tutorial project from Github and it works, but mine doesn't and I can't figure out why...
I'll post some code below (don't mind the Kotlin + Java mix, I tried to implement the security config in java, thought maybe that was a problem)
Initializer.kt
class Initializer : WebApplicationInitializer {
@Throws(ServletException::class)
override fun onStartup(container: ServletContext) {
val context = AnnotationConfigWebApplicationContext()
context.scan("com.newyorkcrew.server.config")
context.scan("com.newyorkcrew.server.domain")
val dispatcher = container.addServlet("dispatcher", DispatcherServlet(context))
dispatcher.setLoadOnStartup(1)
dispatcher.addMapping("/api/*")
}
}
WebConfig.kt
@Bean
fun propertySourcesPlaceholderConfigurer(): PropertySourcesPlaceholderConfigurer {
return PropertySourcesPlaceholderConfigurer()
}
@Configuration
@Import(JPAConfig::class)
@EnableWebMvc
@ComponentScan("com.newyorkcrew.server")
@PropertySources(PropertySource(value = ["classpath:local/db.properties", "classpath:local/security.properties"]))
open class WebConfig {
@Bean
open fun corsConfigurer(): WebMvcConfigurer {
return object : WebMvcConfigurer {
override fun addCorsMappings(registry: CorsRegistry?) {
registry!!.addMapping("/**")
.allowedOrigins("http://localhost:4200", "http://localhost:8080", "http://localhost:8081")
.allowedMethods("GET", "PUT", "POST", "DELETE")
}
}
}
}
WebSecurity.java
@Configuration
@EnableWebSecurity
@ComponentScan("com.newyorkcrew.server.config")
public class WebSecurity extends WebSecurityConfigurerAdapter {
public static String SECRET;
@Value("{security.secret}")
private void setSECRET(String value) {
SECRET = value;
}
@Value("{security.expiration}")
public static long EXPIRATION_TIME;
@Value("{security.header}")
public static String HEADER;
@Value("{security.prefix}")
public static String PREFIX;
public static String SIGN_UP_URL;
@Value("${security.signupurl}")
private void setSignUpUrl(String value) {
SIGN_UP_URL = value;
}
@Autowired
private UserDetailsService userDetailsService;
public WebSecurity(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, SIGN_UP_URL).permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()));
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
I also have implemented the UserDetailService, the JWTAuthenticationFilter and JWTAuthorizationFilter, but as long they're not hit, I don't think that they matter very much.
I've worked with the configs for some time now and they worked, but when the SecurityConfig was added, it's initialised, but the filters don't work for some reason.
If more code is required, I'll post.
EDIT: As requested, the implementation of JWTAuthenticationFilter.
open class JWTAuthenticationFilter(private val authManager: AuthenticationManager) : UsernamePasswordAuthenticationFilter() {
override fun attemptAuthentication(request: HttpServletRequest?, response: HttpServletResponse?): Authentication {
try {
// Build the user DTO from the request
val userDTO = Gson().fromJson(convertInputStreamToString(request?.inputStream), UserDTO::class.java)
// Build the user from the DTO
val user = UserConverter().convertDtoToModel(userDTO)
// Try to authenticate
return authManager.authenticate(UsernamePasswordAuthenticationToken(user.email, user.password, ArrayList()))
} catch (e: Exception) {
throw RuntimeException(e)
}
}
override fun successfulAuthentication(request: HttpServletRequest?, response: HttpServletResponse?,
chain: FilterChain?, authResult: Authentication?) {
val token = Jwts.builder()
.setSubject(authResult?.principal.toString())
.setExpiration(Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS512, SECRET.toByteArray())
.compact()
response?.addHeader(HEADER, "$PREFIX $token")
}
}
Any help is appreciated.
Upvotes: 2
Views: 885
Reputation: 582
The solution that worked for me was to give up Kotlin. Started a fresh Spring project with the same configurations and it simply worked. I'm quite sad as I wanted to do this project in Kt, but maybe I was doing something wrong..
Upvotes: 1