简体   繁体   中英

Spring Security: global method security not working

I have configured Keycloack and my auth server is working fine but since Spring deprecated previous OAuth2 support I am not sure my configuration is acurate. Its a simple learning application and I am trying to add Pre-authorization on method level so that the current authenticated user can add their workout data and view them for themselves. It also restricts delete endpoints only to "fitnessadmin" But I am confused on configuration.

MY Controller class

@RestController
@RequestMapping("/workout")
public class WorkoutController {

    @Autowired
    private WorkoutService workoutService;

    @PostMapping("/")
    public void add(@RequestBody Workout workout) {
        workoutService.saveWorkout(workout);
    }

    @GetMapping("/")
    public List<Workout> findAll() {
        return workoutService.findWorkouts();
    }

    @DeleteMapping("/{id}")
    public void delete(@PathVariable Integer id) {
        workoutService.deleteWorkout(id);
    }
}

the repository class

public interface WorkoutRepository extends JpaRepository<Workout, Integer> {

    @Query("SELECT w FROM Workout w WHERE w.user = ?#{authentication.name}")
    List<Workout> findAllByUser();
}

service class

@Service
public class WorkoutService {
    
    @Autowired
    private WorkoutRepository repository;
    
    @PreAuthorize("#workout.user == authentication.name")
    public void saveWorkout(Workout workout) {
        repository.save(workout);
    }
    
    public List<Workout> findWorkouts() {
        return repository.findAllByUser();
    }
    
    public void deleteWorkout(Integer id) {
        repository.deleteById(id);
    }
    
}

configuration class

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends WebSecurityConfigurerAdapter{
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
          .authorizeRequests(authz -> authz
            .mvcMatchers(HttpMethod.DELETE, "/**").hasAuthority("fitnessadmin")
            .anyRequest().authenticated())
          .oauth2ResourceServer(oauth2 -> oauth2.jwt());
    }
}

application.yaml

server: 
  port: 8086

spring:
  datasource:  
    url: jdbc:mysql://localhost:3306/db2?useSSL=false 
    username: username  
    password: password
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: http://localhost:8080/auth/realms/master
          
claim:
  aud: fitnessapp

I have 3 users as mary, bill, rachel and only mary is "fitnessadmin" and would be able to delete.Rest of the users are "fitnessuser"

Here is the decoded token for bill

{
  "exp" : 1635741988,
  "nbf" : null,
  "iat" : 1635734788,
  "auth_time" : null,
  "jti" : "9b319b1b-7687-4842-b211-02e3d1aaec3c",
  "iss" : "http://localhost:8080/auth/realms/master",
  "aud" : "fitnessapp",
  "sub" : "8fe23dba-d692-4933-9bca-c5f69ff3d408",
  "typ" : "Bearer",
  "azp" : "fitnessapp",
  "nonce" : null,
  "session_state" : "c471f77f-8efa-449b-982d-90ea942f329e",
  "at_hash" : null,
  "c_hash" : null,
  "name" : null,
  "given_name" : null,
  "family_name" : null,
  "middle_name" : null,
  "nickname" : null,
  "preferred_username" : null,
  "profile" : null,
  "picture" : null,
  "website" : null,
  "email" : null,
  "email_verified" : null,
  "gender" : null,
  "birthdate" : null,
  "zoneinfo" : null,
  "locale" : null,
  "phone_number" : null,
  "phone_number_verified" : null,
  "address" : null,
  "updated_at" : null,
  "claims_locales" : null,
  "acr" : "1",
  "s_hash" : null,
  "trusted-certs" : null,
  "allowed-origins" : null,
  "realm_access" : null,
  "resource_access" : null,
  "authorization" : null,
  "cnf" : null,
  "scope" : "fitnessapp",
  "sid" : "c471f77f-8efa-449b-982d-90ea942f329e",
  "user_name" : "bill",
  "authorities" : [ "fitnessuser" ]
}

As I mentioned my confusion is with configuration class. This implementation gives below errors on different endpoints:

findAll():

org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'authentication' cannot be found on object of type 'java.lang.Object[]' - maybe not public or not valid?

add():

403 Forbidden

A help would be greatly appreciated. Thanks in advance!

I guess the error you need to fix is authentication object in query.

public interface WorkoutRepository extends JpaRepository<Workout, Integer> {

    @Query("SELECT w FROM Workout w WHERE w.user = ?#{authentication.name}")
    List<Workout> findAllByUser();
}

Authentication is not an object you can access with this way but if you want to access spring bean you can create Authentication.java and create name field in that class.

Best way will be

public interface WorkoutRepository extends JpaRepository<Workout, Integer> {
    
    @Query("SELECT w FROM Workout w WHERE w.user =:name")
    List<Workout> findAllByUser(@Param("name") String name);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM