目录
1、@PreAuthorize
1.1、寻找@ PreAuthorize
先看一下AuthorizationManager:
AuthorizationManager 取代了 AccessDecisionManager 和 AccessDecisionVoter
@FunctionalInterface
public interface AuthorizationManager<T> {
default void verify(Supplier<Authentication> authentication, T object) {
AuthorizationDecision decision = this.check(authentication, object);
if (decision != null && !decision.isGranted()) {
throw new AccessDeniedException("Access Denied");
}
}
@Nullable
AuthorizationDecision check(Supplier<Authentication> authentication, T object);
}
找到实现类PreAuthorizeAuthorizationManager重写的check()方法:
public AuthorizationDecision check(Supplier<Authentication>
authentication, MethodInvocation mi) {
ExpressionAttribute attribute = this.registry.getAttribute(mi);
if (attribute == ExpressionAttribute.NULL_ATTRIBUTE) {
return null;
} else {
EvaluationContext ctx = this.expressionHandler.createEvaluationContext((Authentication)authentication.get(), mi);
boolean granted = ExpressionUtils.evaluateAsBoolean(attribute.getExpression(), ctx);
return new ExpressionAttributeAuthorizationDecision(granted, attribute);
}
}
其中还有该类中的注册类PreAuthorizeExpressionAttributeRegistry
@NonNull
ExpressionAttribute resolveAttribute(Method method, Class<?> targetClass) {
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
PreAuthorize preAuthorize = this.findPreAuthorizeAnnotation(specificMethod);
if (preAuthorize == null) {
return ExpressionAttribute.NULL_ATTRIBUTE;
} else {
Expression preAuthorizeExpression = PreAuthorizeAuthorizationManager.this.expressionHandler.getExpressionParser().parseExpression(preAuthorize.value());
return new ExpressionAttribute(preAuthorizeExpression);
}
}
private PreAuthorize findPreAuthorizeAnnotation(Method method) {
PreAuthorize preAuthorize = (PreAuthorize)AuthorizationAnnotationUtils.findUniqueAnnotation(method, PreAuthorize.class);
return preAuthorize != null ? preAuthorize : (PreAuthorize)AuthorizationAnnotationUtils.findUniqueAnnotation(method.getDeclaringClass(), PreAuthorize.class);
}
在此终于找到了我们的注解@PreAuthorize
1.2、寻找SecurityExpressionRoot
createEvaluationContext时找到了AbstractSecurityExpressionHandler类:
public final EvaluationContext
createEvaluationContext(Authentication authentication, T invocation) {
SecurityExpressionOperations root = this.createSecurityExpressionRoot(authentication, invocation);
StandardEvaluationContext ctx = this.createEvaluationContextInternal(authentication, invocation);
ctx.setBeanResolver(this.beanResolver);
ctx.setRootObject(root);
return ctx;
}
createSecurityExpressionRoot来自DefaultMethodSecurityExpressionHandler类:
protected MethodSecurityExpressionOperations
createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {
MethodSecurityExpressionRoot root = new MethodSecurityExpressionRoot(authentication);
root.setThis(invocation.getThis());
root.setPermissionEvaluator(this.getPermissionEvaluator());
root.setTrustResolver(this.getTrustResolver());
root.setRoleHierarchy(this.getRoleHierarchy());
root.setDefaultRolePrefix(this.getDefaultRolePrefix());
return root;
}
MethodSecurityExpressionRoot 继承自SecurityExpressionRoot
至此我们终于知道为什么可以在该注解中使用SecurityExpressionRoot中的各种方法。
1.3、用法示例1
@PreAuthorize("hasAuthority('sys:menu:list')")
其中hasAuthority中的url路径是根据业务设计自己定义的
表格中是SecurityExpressionRoot常用方法:
方法 | 用法 |
hasRole(String role) | 判断当前用户是否拥有指定角色 |
hasAuthority(String authority) | 判断当前用户是否拥有指定权限 |
isAuthenticated() | 判断当前用户是否已经通过身份验证 |
2、Spel在@ PreAuthorize的其他用法
2.1、分析
在PreAuthorizeAuthorizationManager的check方法执行时
boolean granted =
ExpressionUtils.evaluateAsBoolean(attribute.getExpression(), ctx);
此处会对Spel表达式进行解析,若表达式中包含SecurityExpressionRoot中的方法则会调用,否则是将其解析为普通的Spel表达式
2.2、用法示例2
@PreAuthorize("@se.hasRole('sys:user:add')")
此处代表调用别名为se的类中的hasRole方法,此处的se为自定义一个bean,可以在其中实现自定义的权限判断逻辑。其中@为Spel表达式中调用bean的意思。
@PreAuthorize("#user.name.equals('haha')")
@PreAuthorize("#id<10")
此处使用方法中的参数进行权限控制,参数可以是实体也可以是基本和包装类型。其中#为Spel表达式中调用方法参数的意思(此处已经由解析器将方法参数注入到Spel上下文中)。
往期精彩: