DomainPermissionChecker,跟Spring設計的有些許不同,我 將Authentication的部分改成了User,且 針對資源性權限參數,省略了Type的傳入。public interface DomainPermissionChecker {
String getTargetType();
// 功能性權限
boolean hasPermission(User user, Object targetDomainObject, String permission);
// 資源性權限
boolean hasPermission(User user, Serializable targetId, String permission);
}
DomainPermissionChecker 的實體Checker,都需要冠上 @Component 的註解,來使其成為Bean。DomainPermissionChecker 是關於實體實作的介面,而 GlobalPermissionEvaluator 則是實作 PermissionEvaluator,並在內部注入 Map<String, DomainPermissionChecker>,此時Spring就會去容器中找到有實作 DomainPermissionChecker 的Bean(這也是為何前一點說要對實體Checker冠上Component的原因)。@Component
public class GlobalPermissionEvaluator implements PermissionEvaluator {
// 管理一組CheckerBeans,key是bean的實體名稱,value就是checkerBean本身
private final Map<String, DomainPermissionChecker> permissionCheckerMap;
@Autowired
public GlobalPermissionEvaluator(List<DomainPermissionChecker> domainPermissionCheckerList){
this.permissionCheckerMap = domainPermissionCheckerList.stream().collect(
Collectors.toMap(
dpc -> dpc.getTargetType().toUpperCase(),
dpc -> dpc
)
);
}
@Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission){
// 先做好null防線,並針對Authentication預先取得User
if (authentication == null || !(authentication.getPrincipal() instanceof User user) || targetDomainObject == null || permission == null){
return false;
}
// 傳入的targetObject先透過getClass取得實體型態名稱
String targetType = targetDomainObject.getClass().getSimpleName().toUpperCase();
// 藉由targetType作為key去找checkerBean
DomainPermissionChecker dpc = permissionCheckerMap.get(targetType);
if (dpc == null) return false;
// 利用剛剛null check的user物件傳入自行設計的DomainPermissionChecker介面
return dpc.hasPermission(user, targetDomainObject, permission.toString());
}
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission){
if (authentication == null || !(authentication.getPrincipal() instanceof User user) || targetId == null || permission == null){
return false;
}
// 針對資源性權限可以直接利用參數的targetType去搜尋鍵值對
DomainPermissionChecker dpc = permissionCheckerMap.get(targetType.toUpperCase());
if (dpc == null) return false;
return dpc.hasPermission(user, targetId, permission.toString());
}
}
本篇文章出自《每天學Java直到今年結束》Day238,大家可以到我的網站上查看~