I have a problem to implement security in my application ... I have custom authentication and use @PreAuthorize to handle my user authorization. This works fine. Now I want to implement Access Control for each user, which means in my application when two users, 'Admin' and 'John', could call method
@RequestMapping(value = "/load/{id}", method = RequestMethod.GET)
@ResponseBody
public StudentYearViewModel load(@PathVariable long id) {
return ModelMapper.map(iStudentService.loadByEntityId(id), StudentViewModel.class);
}
'Admin' can use this method for all Student instances but 'John' can see only his classmate! All users could call this method (@PreAuthorize is not suitable) but their Access is limited HOW do it?? Now have general way?
is ACL best Way?(has best example?)
HDIV framework could help me solve my problem??
what is best solution???
You want to look at @PostFilter
and @PreFilter
. They work pretty much like @PreAuthorize
, but can remove results from lists. You also want to assign different roles to your users, assuming you are not doing that already.
Global rules, like admin being able to see everything, you can implement by writing a concrete implementation of PermissionEvaluator
. You then add that to the MethodSecurityExpressionHandler
Time for a simple example.
This code was written in a text editor. It may not compile and is only here to show the steps needed
A very simplistic PermissionEvaluator
public class MyPermissionEvaluator implements PermissionEvaluator {
private static final SimpleGrantedAuthority AUTHORITY_ADMIN = new SimpleGrantedAuthority('admin');
public boolean hasPermission(final Authentication authentication, final Object classId, final Object permission) {
boolean permissionGranted = false;
// admin can do anything
if (authentication.getAuthorities().contains(AUTHORITY_ADMIN)) {
permissionGranted = true;
} else {
// Check if the logged in user is in the same class
}
return permissionGranted;
}
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType,
Object permission) {
return false;
}
}
Then configure method security
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Bean
public MethodSecurityExpressionHandler methodSecurityExpressionHandler(final PermissionEvaluator permissionEvaluator){
DefaultMethodSecurityExpressionHandler securityExpressionHandler = new DefaultMethodSecurityExpressionHandler();
securityExpressionHandler.setPermissionEvaluator(permissionEvaluator);
return securityExpressionHandler;
}
@Bean
public PermissionEvaluator permissionEvaluator() {
return new MyPermissionEvaluator();
}
}
Now we can use our filter on a method
@PostFilter("hasPermission(filterObject.getClassId(), 'READ')")
@Override
public List<Student> getAll() {
return querySomeStudents();
}
hasPermission
in the @PostFilter
ACL will invoke hasPermission
in MyPermissionEvaluator
. filterObject
refers to the individual items in the list. Wherever you code returns false, it will remove the item from the list.