您现在的位置是:亿华云 > 应用开发
想要控制好权限,这八个注解你必须知道!
亿华云2025-10-09 13:46:36【应用开发】0人已围观
简介小伙伴们知道松哥最近在做 TienChin 项目,项目里涉及到一个问题,那就是数据权限过滤,有不少小伙伴对这个问题觉得特别迷,希望松哥松哥能整一篇文章讲讲,好吧,安排。在讲数据权
小伙伴们知道松哥最近在做 TienChin 项目,想控须知项目里涉及到一个问题,制好那就是权限数据权限过滤,有不少小伙伴对这个问题觉得特别迷,个注希望松哥松哥能整一篇文章讲讲,解必好吧,想控须知安排。制好
在讲数据权限之前,权限我们有必要先和大家介绍一下 Spring Security 中的个注权限注解,把这个捋清楚了,解必再去看 TienChin 项目的想控须知权限注解,你就会发现非常容易了。制好
1. Spring Security 中的权限权限注解
Spring Security 中支持多种权限注解,首先我们需要通过 @EnableGlobalMethodSecurity 注解开启权限注解的个注使用,方式如下:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true,解必securedEnabled = true, jsr250Enabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
}在这个注解中我们一共设置了三个属性:
prePostEnabled:这个表示开启 Spring Security 提供的四个权限注解,@PostAuthorize、@PostFilter、@PreAuthorize 以及 @PreFilter,这四个注解支持权限表达式,支持 SpEL,功能比较丰富。securedEnabled:开启 Spring Security 提供的 @Secured 注解,该注解不支持权限表达式。jsr250Enabled:开启 JSR-250 提供的注解,主要包括 @DenyAll、@PermitAll 以及 @RolesAllowed 三个注解,b2b供应网这些注解也不支持权限表达式。以上这些注解的含义分别如下:
@PostAuthorize:在目标方法执行之后进行权限校验。@PostFilter:在目标方法执行之后对方法的返回结果进行过滤。@PreAuthorize:在目标方法执行之前进行权限校验。@PreFilter:在目标方法执行之前对方法参数进行过滤。@Secured:访问目标方法必须具备相应的角色。@DenyAll:拒绝所有访问。@PermitAll:允许所有访问。@RolesAllowed:访问目标方法必须具备相应的角色。这是所有的,当然一般来说我们只要设置 prePostEnabled=true 就够用了,也就是前四个注解基本上就能满足大部分需求了。
另外还有一种比较“古老”的方法配置基于方法的权限管理,那就是通过 XML 文件配置方法拦截规则,目前已经很少有用 XML 文件来配置 Spring Security 了,所以对于这种方式我们不做过多介绍。感兴趣的小伙伴可以查看官网的相关介绍:https://docs.spring.io/spring-security/ site/docs/5.4.0/reference/html5/#secure-object-impls。
2. 权限注解实践
接下来我们通过几个简单的案例来学习一下上面几种不同注解的用法。
首先创建一个 Spring Boot 项目,云南idc服务商引入 Web 和 Spring Security 依赖,项目创建完成后,添加如下配置文件:
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class SecurityConfig{
}为了方便起见,我们将使用单元测试进行验证,所以这里就不进行额外的配置了,通过 @EnableGlobalMethodSecurity 注解开启其他权限注解的使用即可。
接下来创建一个 User 类以备后续使用:
public class User {
private Integer id;
private String username;
//省略getter/setter
}准备工作完成后,我们来逐个讲解一下前面注解的用法。
2.1 @PreAuthorize@PreAuthorize 注解可以在目标方法执行之前对其进行安全校验,在安全校验时,可以直接使用权限表达式。例如可以定义如下方法:
@Service
public class HelloService {
@PreAuthorize("hasRole(ADMIN)")
public String hello() {
return "hello";
}
}这里使用了权限表达式 hasRole,表示执行该方法必须具备 ADMIN 角色才可以访问,否则不可以访问。接下来我们在单元测试中来测试该方法:
@SpringBootTest
class BasedOnMethodApplicationTests {
@Autowired
HelloService helloService;
@Test
@WithMockUser(roles = "ADMIN")
void preauthorizeTest01() {
String hello = helloService.hello();
assertNotNull(hello);
assertEquals("hello", hello);
}
}通过 @WithMockUser(roles = "ADMIN") 注解设定当前执行的用户角色是 ADMIN,然后调用 helloService 中的方法进行测试即可。如果将用户角色设置为其他字符,那单元测试就不会通过。
当然,这里除了 hasRole 表达式之外,也可以使用其他权限表达式,甚至也可以同时使用多个权限表达式,如下所示:
@Service
public class HelloService {
@PreAuthorize("hasRole(ADMIN) and authentication.name==javaboy")
public String hello() {
return "hello";
}
}表示访问者名称必须是 javaboy,而且还需要同时具备 ADMIN 角色,才可以访问该方法。此时通过如下代码对其进行测试:
@SpringBootTest
class BasedOnMethodApplicationTests {
@Autowired
HelloService helloService;
@Test
@WithMockUser(roles = "ADMIN",username = "javaboy")
void preauthorizeTest01() {
String hello = helloService.hello();
assertNotNull(hello);
assertEquals("hello", hello);
}
}在 @PreAuthorize 注解中,免费信息发布网还可以通过 # 引用方法的参数,并对其进行校验,例如如下方法表示请求者的用户名必须等于方法参数 name 的值,方法才可以被执行:
@PreAuthorize("authentication.name==#name")
public String hello(String name) {
return "hello:" + name;
}测试方法如下:
@Test
@WithMockUser(username = "javaboy")
void preauthorizeTest02() {
String hello = helloService.hello("javaboy");
assertNotNull(hello);
assertEquals("hello:javaboy", hello);
}当模拟的用户名和方法参数相等时,单元测试就可以通过。
2.2 @PreFilter@PreFilter 主要是对方法的请求参数进行过滤,它里边包含了一个内置对象 filterObject 表示要过滤的参数,如果方法只有一个参数,则内置的 filterObject 对象就代表该参数;如果方法有多个参数,则需要通过 filterTarget 来指定 filterObject 到底代表哪个对象:
@PreFilter(value = "filterObject.id%2!=0",filterTarget = "users")
public void addUsers(List
System.out.println("users = " + users);
}上面代码表示对方法参数 users 进行过滤,将 id 为奇数的 user 保留。
然后通过单元测试对该方法进行测试:
@Test
@WithMockUser(username = "javaboy")
void preFilterTest01() {
List
for (int i = 0; i < 10; i++) {
users.add(new User(i, "javaboy:" + i));
}
helloService.addUsers(users, 99);
}执行单元测试方法,addUsers 方法中只会打印出 id 为奇数的 user 对象。
2.3 @PostAuthorize@PostAuthorize 是在目标方法执行之后进行权限校验。可能有小伙伴会觉得奇怪,目标方法都执行完了才去做权限校验意义何在?其实这个主要是在 ACL 权限模型中会用到,目标方法执行完毕后,通过 @PostAuthorize 注解去校验目标方法的返回值是否满足相应的权限要求。
不过呢,即使你的权限模型不是 ACL,也没关系,也有可能用到这个注解,反正记得它的作用:方法执行完成后,根据用户的权限信息过滤出需要返回给用户的数据。
从技术角度来讲,@PostAuthorize 注解中也可以使用权限表达式,但是在实际开发中权限表达式一般都是结合 @PreAuthorize 注解一起使用的。@PostAuthorize 包含一个内置对象 returnObject,表示方法的返回值,开发者可以对返回值进行校验:
@PostAuthorize("returnObject.id==1")
public User getUserById(Integer id) {
return new User(id, "javaboy");
}这个表示方法返回的 user 对象的 id 必须为 1,调用才会顺利通过,否则就会抛出异常。
然后通过单元测试对该方法进行测试:
@Test
@WithMockUser(username = "javaboy")
void postAuthorizeTest01() {
User user = helloService.getUserById(1);
assertNotNull(user);
assertEquals(1,user.getId());
assertEquals("javaboy",user.getUsername());
}如果调用时传入的参数为 1,单元测试就会顺利通过。
2.4 @PostFilter@PostFilter 注解是在目标方法执行之后,对目标方法的返回结果进行过滤,该注解中包含了一个内置对象 filterObject,表示目标方法返回的集合/数组中的具体元素:
@PostFilter("filterObject.id%2==0")
public List
List
for (int i = 0; i < 10; i++) {
users.add(new User(i, "javaboy:" + i));
}
return users;
}这段代码表示 getAll 方法的返回值 users 集合中 user 对象的 id 必须为偶数。
然后我们通过单元测试对其进行测试,代码如下:
@Test
@WithMockUser(roles = "ADMIN")
void postFilterTest01() {
List
assertNotNull(all);
assertEquals(5, all.size());
assertEquals(2,all.get(1).getId());
}2.5 @Secured@Secured 注解也是 Spring Security 提供的权限注解,不同于前面四个注解,该注解不支持权限表达式,只能做一些简单的权限描述。
@Secured({ "ROLE_ADMIN","ROLE_USER"})
public User getUserByUsername(String username) {
return new User(99, username);
}这段代码表示用户需要具备 ROLE_ADMIN 或者 ROLE_USER 角色,才能访问 getUserByUsername 方法。
然后我们通过单元测试对其进行测试,代码如下:
@Test
@WithMockUser(roles = "ADMIN")
void securedTest01() {
User user = helloService.getUserByUsername("javaboy");
assertNotNull(user);
assertEquals(99,user.getId());
assertEquals("javaboy", user.getUsername());
}注意,这里不需要给角色添加 ROLE_ 前缀,系统会自动添加。
2.6 @DenyAll@DenyAll 是 JSR-250 提供的方法注解,看名字就知道这是拒绝所有访问:
@DenyAll
public String denyAll() {
return "DenyAll";
}然后我们通过单元测试对其进行测试,代码如下:
@Test
@WithMockUser(username = "javaboy")
void denyAllTest01() {
helloService.denyAll();
}在单元测试过程中,就会抛出异常。
2.7 @PermitAll@PermitAll 也是 JSR-250 提供的方法注解,看名字就知道这是允许所有访问:
@PermitAll
public String permitAll() {
return "PermitAll";
}然后我们通过单元测试对其进行测试,代码如下:
@Test
@WithMockUser(username = "javaboy")
void permitAllTest01() {
String s = helloService.permitAll();
assertNotNull(s);
assertEquals("PermitAll", s);
}2.8 @RolesAllowed@RolesAllowed 也是 JSR-250 提供的注解,可以添加在方法上或者类上,当添加在类上时,表示该注解对类中的所有方法生效;如果类上和方法上都有该注解,并且起冲突,则以方法上的注解为准。我们来看一个简单的案例:
@RolesAllowed({ "ADMIN","USER"})
public String rolesAllowed() {
return "RolesAllowed";
}这个表示访问 rolesAllowed 方法需要具备 ADMIN 或者 USER 角色,然后我们通过单元测试对其进行测试,代码如下:
@Test
@WithMockUser(roles = "ADMIN")
void rolesAllowedTest01() {
String s = helloService.rolesAllowed();
assertNotNull(s);
assertEquals("RolesAllowed", s);
}这就是常见的方法权限注解。
很赞哦!(55622)
上一篇: 四、一定要仔细阅读细节
下一篇: 3、考虑出售域名
相关文章
- 3、不明先知,根据相关征兆预测可能发生的事件,以便提前做好准备,赶紧注册相关域名。;不差钱域名;buchaqian抢先注册,就是这种敏感类型。预言是最敏感的状态。其次,你应该有眼力。所谓眼力,就是善于从社会上时不时出现的各种热点事件中获取与事件相关的域名资源。眼力的前提是对域名领域的熟悉和丰富的知识。
- 大公司程序员与小公司程序员的区别
- 用PySimpleGUI轻松为程序和脚本添加GUI
- Service Mesh如此火热,背后的技术细节你了解多少?
- 在众多公司中,如果我们必须选择一家可信的公司,那当然是信得过的。
- 程序员这样面试,拿到offer的几率是80%
- 一个故事讲完进程、线程和协程
- 用Python爬了225座城市6758家餐厅,窥探国人吃小龙虾的不同姿势(附代码)
- 什么样的邮箱才是安全的电子邮件地址?
- 关于Vue和React的一些区别
站长推荐
只要我们做的是从目前的市场情况选择域名,从简单易记,从个性特征上,我们就可以找到一个好域名进行注册。域名注册进行域名记录和解析以及绑定网站后,客户可以通过URL登录您的网站。
视+AR创始人张小军告诉你建设AR平台的正确姿势
你是否正处于35岁之殇?一文鉴定并解除危机!
用Promise讲一个悲伤的故事给你听
域名资源有限,好域名更是有限,但机会随时都有,这取决于我们能否抓住机会。一般观点认为,国内域名注册太深,建议优先考虑外国注册人。外国注册人相对诚实,但价格差别很大,从几美元到几十美元不等。域名投资者应抓住机遇,尽早注册国外域名。
Mesh?无线协议的选择
90%的 Java 程序员被误导的一个性能优化策略!
GitHub 宣布 GitHub Education 新计划,学校可免费用企业版