这几天好忙呀!
忙的时候有点烦躁(别来惹我!),闲的时候又有点发慌(都来惹我呀!),哈哈!
最近在忙增删改查,为了节约代码,一个控制器供好几个菜单访问,这就用到了权限控制,想不起来用哪个表达式,来,一起翻一下。
Spring Security 提供了基于 Spring 表达式语言 (Spring EL) 的权限控制能力,可用于 URL 访问、方法调用等场景,支持灵活的动态权限校验。主要内容包括:URL 权限控制、方法权限控制、自定义表达式扩展等。
先来看内置表达式有哪些?
一、内置表达式
在Spring Security框架中,SecurityExpressionRoot(安全表达式基类)提供了一些内置表达式。
这些内置表达式可以拿来即用,不需要额外配置。
接下来看应用。
二、URL 权限控制
通过HttpSecurity对象配置 URL 权限控制。启用表达式支持后,可以结合用户角色、IP 地址等条件进行细粒度的权限校验。
1、基本配置
配置示例:允许具有ROLE_USER角色的用户访问所有 URL。
@Overrideprotected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/**").access("hasRole('ROLE_USER')") .and() .formLogin() .and() .logout();}
2、基于 IP 地址的访问控制
允许特定 IP 地址的用户访问资源:
@Overrideprotected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/**").hasIpAddress("192.168.0.15") .and() .formLogin() .and() .logout();}
3、案例:基于子网的访问控制
允许192.168.1.0/24网段内的用户访问:
@Overrideprotected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/**").hasIpAddress('192.168.1.0/24') .and() .formLogin() .and() .logout();}
三、 方法权限控制
Spring Security 提供了 4 种注解,用于在方法级别实现权限控控制@PreAuthorize、@PostAuthorize、@PreFilter、@PostFilter。
3.1 方法调用前的权限校验
@PreAuthorize用于在方法调用前进行权限检查。
案例 1:基于角色的权限控制
仅允许具有ROLE_ADMIN角色的用户调用addUser方法。
@RestControllerpublic class UserController { @PreAuthorize("hasRole('ROLE_ADMIN')") public void addUser(User user) { // 添加用户逻辑 }}
如果匹配的权限为ROLE_ADMIN 或 ROLE_ADMIN1,可以使用hasAnyRole('ROLE_ADMIN','ROLE_ADMIN1') 或hasRole('ROLE_ADMIN') or hasRole('ROLE_ADMIN1')。
案例 2:基于参数的权限控制
限制只能查询 ID 小于 10 的用户。
@RestControllerpublic class UserController { @PreAuthorize("#id < 10") public User findUserById(int id) { return new User(id); }}
3.2 方法调用后的权限校验
@PostAuthorize用于在方法执行完成后对返回结果进行权限检查。
案例:检查返回结果,仅当返回对象的 ID 为偶数时允许访问。
@PostAuthorize("returnObject.id % 2 == 0")public User getUser(int id) { return new User(id);}
3.3 集合过滤
使用@PreFilter和@PostFilter对集合类型的参数或返回值进行过滤。
案例:返回结果过滤,仅返回 ID 为偶数的用户。
@PostFilter("filterObject.id % 2 == 0")public List<User> getUsers() { return List.of(new User(1), new User(2), new User(3), new User(4));}
四、 自定义权限表达式
如果内置的表达式无法满足需求,可以通过实现PermissionEvaluator接口来自定义权限逻辑。
1、实现自定义 PermissionEvaluator
以下代码实现了简单的字符串匹配逻辑:
@Configurationpublic class MyPermissionEvaluator implements PermissionEvaluator { @Override public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) { boolean accessable = false; //匿名访问时,无权限 if(authentication.getPrincipal().toString().compareToIgnoreCase("anonymousUser") != 0){ //中间用冒号分隔 String privilege = targetDomainObject + ":" + permission; for(GrantedAuthority authority : authentication.getAuthorities()){ if(privilege.equalsIgnoreCase(authority.getAuthority())){ accessable = true; break; } } return accessable; } return accessable; } /** * 总是认为有权限返回true,否则返回false */ @Override public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) { return false; }}
2、应用自定义表达式
在方法级别使用自定义表达式:
@PreAuthorize("hasPermission('user', 'ROLE_USER')")public User getUser(int id) { return new User(id);}
最后总结
Spring Security 的基于表达式的权限控制功能强大而灵活,可通过内置与自定义表达式满足复杂权限需求。
时间匆忙,稍微整理一下,有些示例代码还需要交给时间检验。
领取专属 10元无门槛券
私享最新 技术干货