I am trying to implement Role Based Authentication and Authorization in an LMMS but after configuration, I made signup request with Postman and I kept on having Unauthorized Error
: Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed in public edu.eduforge.lmms.controller.AuthApi(org.springframework.security.authentication.AuthenticationManager,edu.eduforge.lmms.repository.UserRepository,org.springframework.security.crypto.password.PasswordEncoder,edu.eduforge.lmms.security.jwt.JwtUtils): [Error in object 'edu.eduforge.lmms.controller.AuthApi': codes []; arguments []; default message [Parameter specified as non-null is null: method edu.eduforge.lmms.controller.AuthApi.<init>, parameter authenticationManager]] ]
Unauthorized error: Full authentication is required to access this resource
I have check online and try chatGPT but the stay wont go
Here is my Code
@RestController
@RequestMapping("/api_v1/auth")
class AuthApi(
private val authenticationManager: AuthenticationManager,
private val userRepository: UserRepository,
private val passwordEncoder: PasswordEncoder,
private val jwtUtils: JwtUtils
) {
@PostMapping("/signin")
fun authenticateUser(@Valid @RequestBody loginRequest: LoginRequest): ResponseEntity<*>{
val authentication: Authentication = authenticationManager.authenticate(
UsernamePasswordAuthenticationToken(loginRequest.username, loginRequest.password)
)
// Setting the context for current user
SecurityContextHolder.getContext().authentication = authentication
// Getting jwt token for current user
val jwt: String = jwtUtils.generateJwtToken(authentication)
val userDetails: UserDetailsImpl = authentication.principal as UserDetailsImpl
val roles: List<String> = userDetails.authorities.stream()
.map { item -> item.authority }
.collect(Collectors.toList())
return ResponseEntity.ok(JwtResponse(
jwt,
userDetails.getId(),
userDetails.username,
userDetails.getEmail(),
roles
))
@PostMapping("/signup")
fun registerUser(@Valid @RequestBody signupRequest: SignupRequest): ResponseEntity<*>{
if(userRepository.existsByUsername(signupRequest.username)){
return ResponseEntity.badRequest()
.body( MessageResponse("Error: Username is already taken!"))
}
if(userRepository.existsByEmail(signupRequest.email)){
return ResponseEntity.badRequest()
.body( MessageResponse("Error: Email is already taken!"))
}
//create new User's account
val strRoles: Set<String> = signupRequest.roles
var roles: MutableSet<Role> = HashSet();
if(strRoles ==null){
roles.add(Role(appEnums.ERole.USER_ANONYMOUS))
}else{
strRoles.forEach { role ->
run {
if (role == "admin") {
roles.add(Role(appEnums.ERole.USER_ADMIN))
}
else if (role == "student"){
roles.add(Role(appEnums.ERole.USER_STUDENT))
} else if(role == "instructor"){
roles.add(Role(appEnums.ERole.USER_INSTRUCTOR))
}
else{
roles.add(Role(appEnums.ERole.USER_ANONYMOUS))
}
}
}
}
val user = User().apply{
firstName = signupRequest.firstName
lastName = signupRequest.lastName
username = signupRequest.username
email = signupRequest.email
password = passwordEncoder.encode(signupRequest.password)
roles = roles
}
//saving to database
userRepository.save(user)
return ResponseEntity.ok(MessageResponse("User registered successfully!"))
}
}
}
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(
// secureEnable = true
// jsr250Enabled = true
prePostEnabled = true
)
class WebSecurityConfig(
private val userDetailsService: UserDetailsServiceImpl,
private val unauthorizedHandler: AuthEntryPointJwt
) {
@Bean
fun authenticationJwtTokenFilter(): AuthTokenFilter {
return AuthTokenFilter();
}
@Throws(Exception::class)
fun configure(auth: AuthenticationManagerBuilder?){
auth?.userDetailsService(userDetailsService)?.passwordEncoder(passwordEncoder())
}
@Bean
@Throws(Exception::class)
fun authenticationManagerBean(authConfiguration: AuthenticationConfiguration): AuthenticationManager? {
return authConfiguration.authenticationManager
}
@Bean
fun passwordEncoder(): PasswordEncoder {
return BCryptPasswordEncoder();
}
@Bean
fun configure(http: HttpSecurity): DefaultSecurityFilterChain? {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeHttpRequests().requestMatchers("/api_v1/auth/**").permitAll()
.requestMatchers("/api_v1/test/**").permitAll()
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter::class.java)
return http.build()
}
}
@Component
class AuthEntryPointJwt : AuthenticationEntryPoint {
@Throws(IOException::class, ServletException::class)
override fun commence(request: HttpServletRequest?, response: HttpServletResponse?, authException: AuthenticationException?) {
//SC_UNAUTHORIZED is 401 status code
println("Unauthorized error: ${authException?.message}")
response?.sendError(HttpServletResponse.SC_UNAUTHORIZED,"Error: Unauthorized")
}
}
How do I fix "Unauthorized error: Full authentication is required to access this resource in Kotlin Springboot Web Service" ?