1
package com.hexa.amazecare.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.hexa.amazecare.dto.DoctorDTO;
import com.hexa.amazecare.service.DoctorService;

@RestController
@RequestMapping("/api/doctors")
public class DoctorController {

    @Autowired
    private DoctorService doctorService;

    // Get doctor by ID
    @GetMapping("/get/{id}")
    public ResponseEntity<DoctorDTO> getDoctorById(@PathVariable Long id) {
        DoctorDTO doctorDTO = doctorService.getDoctorById(id);
        return ResponseEntity.ok(doctorDTO);
    }
    
    //get doctors by Specialty
    @GetMapping("/get-specialty/{speciality}")
    public ResponseEntity<List<DoctorDTO>> getDoctorBySpecality(@PathVariable String specialty) {
        List<DoctorDTO> doctors = doctorService.getDoctorBySpecality(specialty);
        return ResponseEntity.ok(doctors);
    }

    // Endpoint to get all doctors
    @GetMapping("/get")
    public ResponseEntity<List<DoctorDTO>> getAllDoctors() {
        List<DoctorDTO> doctors = doctorService.getAllDoctors();
        return ResponseEntity.ok(doctors);
    }

    // Create a new doctor
    @PostMapping("/add")
    public ResponseEntity<DoctorDTO> createDoctor(@RequestBody DoctorDTO doctorDTO) {
        DoctorDTO newDoctor = doctorService.createDoctor(doctorDTO);
        return ResponseEntity.ok(newDoctor);
    }

    // Update an existing doctor
    @PutMapping("update/{id}")
    public ResponseEntity<DoctorDTO> updateDoctor(@PathVariable Long id, @RequestBody DoctorDTO doctorDTO) {
        DoctorDTO updatedDoctor = doctorService.updateDoctor(id, doctorDTO);
        return ResponseEntity.ok(updatedDoctor);
    }

    // Delete a doctor by ID
    @DeleteMapping("delete/{id}")
    public ResponseEntity<Void> deleteDoctor(@PathVariable Long id) {
        doctorService.deleteDoctor(id);
        return ResponseEntity.noContent().build();
    }
    
 // Endpoint to retrieve all specialties
    @GetMapping("/specialties")
    public ResponseEntity<List<String>> getAllSpecialties() {
        List<String> specialties = doctorService.getAllSpecialties();
        return ResponseEntity.ok(specialties);
    }
}

So I have these endpoints in a doctor controller class, while all the endpoints work after authorization perfectly, the "getDoctorBySpecality" endpoint doesn't give appropriate result. It gives a 401 unauthorized error.

Here's my security config for further context:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

    return http.csrf(csrf -> csrf.disable())
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/auth/**").permitAll() // Allow access to registration and login
                .requestMatchers("api/patients/get/**").hasAnyRole("DOCTOR","PATIENT","ADMIN")
                .requestMatchers("/api/patients/**").hasAnyRole("PATIENT","DOCTOR","ADMIN") 
                .requestMatchers("/api/doctors/get-specialty/").hasAnyRole("DOCTOR","PATIENT","ADMIN")
                .requestMatchers("/api/doctors/**").hasAnyRole("DOCTOR","PATIENT","ADMIN")
                .anyRequest().authenticated() // All other requests require authentication
            )
            .cors(Customizer.withDefaults())
            .httpBasic(Customizer.withDefaults())
            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
            .build();
}

I tried accessing my endpoint from my Postman and got the 401 unauthorized error. I am a beginner at Spring Boot, so I am not sure where I am going wrong.

2 Answers 2

1

Always use /** at the end of a matcher like you did for the other endpoints when you want to allow access to routes that include additional segments, eg {id}

Here you missed /**:

.requestMatchers("/api/doctors/get-specialty/").hasAnyRole("DOCTOR","PATIENT","ADMIN")

It should be:

.requestMatchers("/api/doctors/get-specialty/**").hasAnyRole("DOCTOR","PATIENT","ADMIN")

Also

@GetMapping("/get-specialty/{speciality}")
public ResponseEntity<List<DoctorDTO>> getDoctorBySpecality(@PathVariable String specialty) {
    List<DoctorDTO> doctors = doctorService.getDoctorBySpecality(specialty);
    return ResponseEntity.ok(doctors);
}

You have a typo in the path - {speciality} change to {specialty}.

Sign up to request clarification or add additional context in comments.

3 Comments

Hey Thank you for your Response! I've tried that but it didn't resolve the issue. But I've found a new clue to the issue When I try to access the endpoint I get the following error in my console: 2024-10-04T23:05:15.907+05:30[0;39m [33m WARN[0;39m [35m18748[0;39m [2m---[0;39m [2m[AmazeCare] [nio-8080-exec-3][0;39m [2m[0;39m[36m.w.s.m.s.DefaultHandlerExceptionResolver[0;39m [2m:[0;39m Resolved [org.springframework.web.bind.MissingPathVariableException: Required URI template variable 'specialty' for method parameter type String is not present]
This is the example url which I used localhost:8080/api/doctors/get-specialty/"cardiology"
Updated my answer U got a typo. @GetMapping("/get-specialty/{speciality}")
0

Try changing:

.requestMatchers("/api/doctors/get-specialty/").hasAnyRole("DOCTOR","PATIENT","ADMIN")

to

.requestMatchers("/api/doctors/get-specialty").hasAnyRole("DOCTOR","PATIENT","ADMIN")

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.