小伙伴们知道,在 Shiro 中,默认是支持权限通配符的,例如系统用户有如下一些权限:
- system:user:add
- system:user:delete
- system:user:select
- system:user:update
- ...
现在给用户授权的时候,我们可以像上面这样,一个权限一个权限的配置,也可以直接用通配符:
- system:user:*
这个通配符就表示拥有针对用户的所有权限。
当然这是 Shiro 里边的,对 Shiro 不熟悉的小伙伴,可以在公众号后台回复 shiro,查看松哥之前录的视频教程。
今天我们来聊聊 Spring Security 中对此如何处理,也顺便来看看 TienChin 项目中,这块该如何改进。
1. SpEL
要搞明白基于注解的权限管理,那么得首先理解 SpEL,不需要了解多深入,我这里就简单介绍下。
Spring Expression Language(简称 SpEL)是一个支持查询和操作运行时对象导航图功能的强大的表达式语言。它的语法类似于传统 EL,但提供额外的功能,最出色的就是函数调用和简单字符串的模板函数。
SpEL 给 Spring 社区提供一种简单而高效的表达式语言,一种可贯穿整个 Spring 产品组的语言。这种语言的特性基于 Spring 产品的需求而设计,这是它出现的一大特色。
在我们离不开 Spring 框架的同时,其实我们也已经离不开 SpEL 了,因为它太好用、太强大了,SpEL 在整个 Spring 家族中也处于一个非常重要的位置。但是很多时候,我们对它的只了解一个大概,其实如果你系统的学习过 SpEL,那么上面 Spring Security 那个注解其实很好理解。
我先通过一个简单的例子来和大家捋一捋 SpEL。
为了省事,我就创建一个 Spring Boot 工程来和大家演示,创建的时候不用加任何额外的依赖,就最最基础的依赖即可。
代码如下:
String expressionStr = "1 + 2";
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(expressionStr);
expressionStr 是我们自定义的一个表达式字符串,这个字符串通过一个 ExpressionParser 对象将之解析为一个 Expression,接下来就可以执行这个 exp 了。
执行的时候有两种方式,对于我们上面这种不带任何额外变量的,我们可以直接执行,直接执行的方式如下:
Object value = exp.getValue();
System.out.println(value.toString());
这个打印结果为 3。
我记得之前有个小伙伴在群里问想执行一个字符串表达式,但是不知道怎么办,js 中有 eval 函数很方便,我们 Java 中也有 SpEL,一样也很方便。
不过很多时候,我们要执行的表达式可能比较复杂,这时候上面这种调用方式就不太够用了。
此时我们可以为要调用的表达式设置一个上下文环境,这个时候就会用到 EvaluationContext 或者它的子类,如下:
StandardEvaluationContext context = new StandardEvaluationContext();
System.out.println(exp.getValue(context));
当然上面这个表达式不需要设置上下文环境,我举一个需要设置上下文环境的例子。
例如我现在有一个 User 类,如下:
public class User {
private Integer id;
private String username;
private String address;
//省略 getter/setter
}
现在我的表达式是这样:
String expression = "#user.username";
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(expression);
StandardEvaluationContext ctx = new StandardEvaluationContext();
User user = new User();
user.setAddress("广州");
user.setUsername("javaboy");
user.setId(99);
ctx.setVariable("user", user);
String value = exp.getValue(ctx, String.class);
Syste