

?【Spring专题】「实战系列」Spring Security技术实战之通过注解表达式控制方法权限
source link: https://my.oschina.net/liboware/blog/5439832
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Spring Security权限控制机制
Spring Security中可以通过表达式控制方法权限,其中有四个支持使用表达式的注解,分别是@PreAuthorize、@PostAuthorize、@PreFilter和@PostFilter。其中前两者可以用来在方法调用前或者调用后进行权限检查,后两者可以用来对集合类型的参数或者返回值进行过滤。
启动Security机制的配置
它们的定义能够对我们的方法的调用产生影响我们需要设置global-method-security元素的pre-post-annotations=”enabled”,默认为disabled。
xml配置方式
<security:global-method-security pre-post-annotations="disabled"/>
JavaConfig配置方式
类上增加@EnableGlobalMethodSecurity(securedEnabled = true)注解,secureEnabled默认为false,使其赋值为true才能使用相关注解。
@SpringBootApplication
@EnableGlobalMethodSecurity(securedEnabled = true)
public class XXXApplication {
public static void main(String[] args) {
SpringApplication.run(XXXApplication.class, args);
}
}
@PreAuthorize和@PostAuthorize进行访问控制
@PreAuthorize 注解,顾名思义是进入方法前的权限验证,@PreAuthorize 声明这个方法所需要的权限表达式,例如:@PreAuthorize("hasAuthority('sys:dept:delete')"),@PreAuthorize 表示访问方法或类在执行之前先判断权限,一般都是使用这个注解,注解的参数和access()方法参数取值相同,都是权限表达式。若有多个权限,可用逗号隔开。
根据这个注解所需要的权限,再和当前登录的用户角色所拥有的权限对比,如果用户的角色权限集Set中有这个权限,则放行;没有,拒绝
@GetMapping("/query")
//以下几个注解都表示ADMIN用户具有访问"/query"接口的权限
@PreAuthorize("hasAnyRole('ADMIN')")
@Secured("ROLE_ADMIN")//以ROLE_开头,不能缺少
@PostAuthorize("hasAnyRole('ADMIN')")
public String query(){
return "querySuccess";
}
定义相关的接口上
public interface UserService {
public boolean ifhaveuser(String username,String password);
List<User> findAllUsers();
User findById(int id);
@PreAuthorize("hasRole('ROLE_ADMIN')")
void updateUser(User user);
@PreAuthorize("hasRole('ROLE_ADMIN')")
void deleteUser(int id);
}
@Service
public class UserServiceImpl implements UserService {undefined
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void addUser(User user) {undefined
System.out.println("addUser................" + user);
}
@PreAuthorize("hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')")
public User find(int id) {undefined
System.out.println("find user by id............." + id);
return null;
}
}
在上面的代码中我们定义了只有拥有角色ROLE_ADMIN的用户才能访问adduser()方法,而访问find()方法需要有ROLE_USER角色或ROLE_ADMIN角色。使用表达式时我们还可以在表达式中使用方法参数。
PreAuthorize的EL表达式
public class UserServiceImpl implements UserService {undefined
/**
* 限制只能查询Id小于10的用户
*/
@PreAuthorize("#id<10")
public User find(int id) {undefined
System.out.println("find user by id........." + id);
return null;
}
/**
* 限制只能查询自己的信息
*/
@PreAuthorize("principal.username.equals(#username)")
public User find(String username) {undefined
System.out.println("find user by username......" + username);
return null;
}
/**
* 限制只能新增用户名称为abc的用户
*/
@PreAuthorize("#user.name.equals('abc')")
public void add(User user) {undefined
System.out.println("addUser............" + user);
}
}
在上面代码中我们定义了调用find(int id)方法时,只允许参数id小于10的调用;调用find(String username)时只允许username为当前用户的用户名;定义了调用add()方法时只有当参数user的name为abc时才可以调用。
- @Secured使用时必须要加上ROLE_前缀,不可省略。@PreAuthorize 也可加上ROLE_前缀,不过其可以省略。
用户的角色权限Set,是什么时候存入的,其流程如下
PostAuthorize的EL表达式
- @PostAuthorize表示方法或类执行结束后判断权限,很少使用。
有时候可能你会想在方法调用完之后进行权限检查,这种情况比较少,但是如果你有的话,Spring Security也为我们提供了支持,通过@PostAuthorize可以达到这一效果。使用@PostAuthorize时我们可以使用内置的表达式returnObject表示方法的返回值。
下面这一段示例代码:
@PostAuthorize("returnObject.id%2==0")
public User find(int id) {undefined
User user = new User();
user.setId(id);
return user;
}
上面这一段代码表示将在方法find()调用完成后进行权限检查,如果返回值的id是偶数则表示校验通过,否则表示校验失败,将抛出AccessDeniedException。
注意的是@PostAuthorize是在方法调用完成后进行权限检查,它不能控制方法是否能被调用,只能在方法调用完成后检查权限决定是否要抛出AccessDeniedException。
@PreFilter和@PostFilter进行过滤
使用@PreFilter和@PostFilter可以对集合类型的参数或返回值进行过滤。使用@PreFilter和@PostFilter时,Spring Security将移除使对应表达式的结果为false的元素。
@PostFilter("filterObject.id%2==0")
public List<User> findAll() {undefined
List<User> userList = new ArrayList<User>();
User user;
for (int i=0; i<10; i++) {undefined
user = new User();
user.setId(i);
userList.add(user);
}
return userList;
}
上述代码表示将对返回结果中id不为偶数的user进行移除。filterObject是使用@PreFilter和@PostFilter时的一个内置表达式,表示集合中的当前对象。当@PreFilter标注的方法拥有多个集合类型的参数时,需要通过@PreFilter的filterTarget属性指定当前@PreFilter是针对哪个参数进行过滤的。
Recommend
-
30
Redis是一个开源,高级的键值存储和一个适用的解决方案,用于构建高性能,可扩展的Web应用程序。本文将概要介绍Redis的特性和语法,并以实例代码的形式介绍如何通过Jedis在java语言环境下控制Redis,帮助各位读者快速入门。
-
15
只要下定决心,过去的失败,正好是未来行动的借鉴;只要不屈不挠,一时的障碍,正好是推动成功的力量。 之前写完了一篇关于Lambda系列的原理分析【
-
12
Java的class字节码并不是机器语言,要想让机器能够执行,还需要把字节码翻译成机器指令。这个过程是Java虚拟机做的,这个过程也叫编译。是更深层次的编译。 在编译原理中,把源代码翻译成机器指令,一般要经过以下几个重要步骤: 根据完成任务...
-
13
昨天有个粉丝加了我,问我如何实现类似shiro的资源权限表达式的访问控制。我以前有一个小框架用的就是shiro,权限控制就用了资源权限表达式,所以这个东西对我不陌生,但是在Spring Security中我并没有使用过它,不过我认为Spring Security可以实现这一点。是的...
-
10
【SpringCloud技术专题】「入门实战」微服务网关服务的Gateway全流程开发实践指南 推荐 原创 洛神灬殇
-
3
logback的maven配置 xml<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version&...
-
7
【SpringBoot技术专题】「开发实战系列」一起搭建属于自己的SpringBoot Admin的技术要素 精选 原创
-
11
SpringBoot快速操作Redis数据 在SpringBoot框架中提供了spring-boot-starter-data-redis的依赖组件进行操作Redis服务,当引入了该组件之后,只需要配置Redis的配置即可进行链接Redis服务并且进行操作Red...
-
9
Redis基本简介Redis是一个开源(BSD 许可)、内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。它支持字符串、哈希表、列表、集合、有序集合等数据类型。内置复制、Lua 脚本、LRU收回、事务以及不同级别磁盘持久化功能,同时通过...
-
5
Redis基本简介 Redis是一个开源(BSD 许可)、内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。它支持字符串、哈希表、列表、集合、有序集合等数据类型。内置复制、Lua 脚本、LRU收回、事务以及不同级别磁盘持久化功...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK