Spring Security 中对于权限控制默认已经提供了很多了,但是,一个优秀的框架必须具备良好的扩展性,恰好,Spring Security 的扩展性就非常棒,我们既可以使用 Spring Security 提供的方式做授权,也可以自定义授权逻辑。一句话,你想怎么玩都可以!
Spring Security 中四种常见的权限控制方式。
- 表达式控制 URL 路径权限
- 表达式控制方法权限
- 使用过滤注解
- 动态权限
表达式控制 URL 路径权限
Spring Security 支持在 URL 和方法权限控制时使用 SpEL 表达式,如果表达式返回值为 true 则表示需要对应的权限,否则表示不需要对应的权限。提供表达式的类是 SecurityExpressionRoot:
使用案例
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/user/**").hasAnyRole("admin", "user")
.anyRequest().authenticated()
.and()
...
}
这里表示访问 /admin/** 格式的路径需要 admin 角色,访问 /user/** 格式的路径需要 admin 或者 user 角色。
表达式控制方法权限
在方法上添加注解控制权限,需要我们首先开启注解的使用,在 Spring Security 配置类上添加如下内容:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
...
}
这个配置开启了三个注解,分别是:
- @PreAuthorize:方法执行前进行权限检查
- @PostAuthorize:方法执行后进行权限检查
- @Secured:类似于 @PreAuthorize
使用案例
@Service
public class HelloService {
@PreAuthorize("principal.username.equals('chenfu')")
public String hello() {
return "hello";
}
@PreAuthorize("hasRole('admin')")
public String admin() {
return "admin";
}
@PostMapping
@ApiOperation(value = "等级变更记录分页列表")
@PreAuthorize("@ato.hasAuthority('msg')")
public String customer(String msg) {
return "customer:" + msg;
}
}
@Slf4j
@Component("ato")
public class AuthorityService {
/**
* 判断接口是否有ato:xxxxx,xxxxx权限
*
* @param permissions 权限标识
* @return {boolean}
*/
public boolean hasAuthority(String... permissions) {
if (ArrayUtil.isEmpty(permissions)) {
return false;
}
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
return false;
}
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
return authorities.stream()
.map(GrantedAuthority::getAuthority)
.filter(StringUtils::hasText)
.anyMatch(x -> PatternMatchUtils.simpleMatch(permissions, x));
}
}
- 第一个 hello 方法,注解的约束是,只有当前登录用户名为 chenfu 的用户才可以访问该方法。
- 第二个 admin 方法,表示访问该方法的用户必须具备 admin 角色。
- 第三个 customer 方法,使用自定义类处理逻辑,校验登录用户是否具备接口权限
缺省对象除了 principal ,还有 authentication
使用过滤注解
Spring Security 中还有两个过滤函数 @PreFilter 和 @PostFilter,可以根据给出的条件,自动移除集合中的元素。
@PostFilter("filterObject.lastIndexOf('2')!=-1")
public List<String> getAllUser() {
List<String> users = new ArrayList<>();
for (int i = 0; i < 10; i++) {
users.add("chenfu:" + i);
}
return users;
}
@PreFilter(filterTarget = "ages",value = "filterObject%2==0")
public void getAllAge(List<Integer> ages,List<String> users) {
System.out.println("ages = " + ages);
System.out.println("users = " + users);
}
- 在 getAllUser 方法中,对集合进行过滤,只返回后缀为 2 的元素,filterObject 表示要过滤的元素对象。
- 在 getAllAge 方法中,由于有两个集合,因此使用 filterTarget 指定过滤对象。
动态权限
引用
- Spring Security 中的四种权限控制方式