要触发PermissionEvaluator,您必须在@PreAuthorize 中使用hasPermission()。
hasPermission() 有 2 个版本:
(1) @PreAuthorize("hasPermission('foo' ,'bar')") 将调用
boolean hasPermission(Authentication authentication, Object targetDomainObject,Object permission);
/** targetDomainObject = 'foo', permission = 'bar' **/
(2) @PreAuthorize("hasPermission('foo' ,'bar','baz')") 将调用
boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission);
/** targetId = 'foo' , targetType = 'bar' , permission = 'baz' **/
在这两种情况下,Authentication 参数都是从SecurityContext 获取的Authentication 令牌。
需要注意的是,在配置@PreAuthorize("hasPermission()")时,可以使用spring数据中的#foo、@P或@Param来指定protected方法中的哪个参数将用于调用PermissionEvaluator。详情请见this。
在您的情况下,您可以执行以下操作:
@PreAuthorize("hasPermission('#id', 'getOrder')")
public EntityModel<Order> getOrders(@PathVariable Long id) {
}
PermissionEvaluator 看起来像:
public class MyPermissionEvaluator implements PermissionEvaluator {
@Override
public boolean hasPermission(Authentication auth, Object targetDomainObject, Object permission) {
MyAuthentication myAuth = (MyAuthentication) auth;
Long targetId = (Long) id;
String permssionStr = (String) permission;
if(permssionStr.equals("getOrder")){
return myAuth.getUserId().equals(targetId);
}else if(permssionStr.equals("xxxx"){
//other permission checking
}
}
}
请注意,它假设您还将Authentication 令牌自定义为MyAuthentication,其中包括用户ID。它还回答了您的第二个问题,即您可以自定义身份验证过程以返回自定义的Authentication 令牌,您可以在加载用户记录以进行身份验证后将 userId 设置到其中。这样userId就会被存储在MyAuthentication里面,你不需要在PermissionEvaluator里面再次查询。
另外,你也可以考虑直接在@PreAuthorize中表达授权逻辑,这样简单的情况不用hasPermission():
@PreAuthorize("#id == authentication.userId")
public EntityModel<Order> getOrders(@PathVariable Long id) {
}