#6解析@PreAuthorize以及其中的Spel

目录

1、@PreAuthorize

1.1、寻找@ PreAuthorize

1.2、寻找SecurityExpressionRoot

1.3、用法示例1

2、Spel在@ PreAuthorize的其他用法

2.1、分析

2.2、用法示例2



往期精彩:

#1maven打包时指定profile过滤resources的一些总结-CSDN博客

#2Vite+Vue3+SpringMVC前后端分离 解决跨域问题和session每次请求不一致问题-CSDN博客

#3Jenkins(Windows环境)版本升级、迁移、负载均衡、双机器同步与备份-CSDN博客

#4详解@RequestParam、@RequestBody和@PathVariable-CSDN博客

#5解析filter为什么不能注入bean和解决办法以及filter、interceptor、aspect之间的执行顺序-CSDN博客

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上下文中)。

如果对你有帮助,点赞、收藏、关注是我更新的动力!

相关推荐

  1. #6解析@PreAuthorize以及其中Spel

    2024-01-16 19:00:01       65 阅读
  2. SpEL 使用

    2024-01-16 19:00:01       61 阅读
  3. Spring SpEL在Flink中应用-SpEL详解

    2024-01-16 19:00:01       50 阅读
  4. MapReduce执行过程(以及其中排序)

    2024-01-16 19:00:01       61 阅读
  5. Objective-C 中SEL

    2024-01-16 19:00:01       45 阅读
  6. Spel 表达式

    2024-01-16 19:00:01       44 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-16 19:00:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-16 19:00:01       101 阅读
  3. 在Django里面运行非项目文件

    2024-01-16 19:00:01       82 阅读
  4. Python语言-面向对象

    2024-01-16 19:00:01       91 阅读

热门阅读

  1. Sentinel

    Sentinel

    2024-01-16 19:00:01      45 阅读
  2. 连接世界:2024 年 5G 及未来技术趋势

    2024-01-16 19:00:01       57 阅读
  3. Qt下载http文件

    2024-01-16 19:00:01       63 阅读
  4. cf-913-div3

    2024-01-16 19:00:01       67 阅读
  5. Kotlin withContext详解与suspend和inline

    2024-01-16 19:00:01       47 阅读
  6. UML类图

    UML类图

    2024-01-16 19:00:01      52 阅读
  7. 前端笔试题(一)

    2024-01-16 19:00:01       53 阅读