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.