文章
问答
冒泡
在spring实现方法级权限控制

在业务中,我们会需要对一些操作进行用户级别的权限控制,例如,根据ID删除某条数据的时候,如果该数据并不是当前用户创建的,那么直接被删除了,显然是不合理的,这个时候,我们就需要对操作进行用户级别的权限控制。

1.基于spring security实现
开启配置

@EnableGlobalMethodSecurity(prePostEnabled = true)


基于@PreAuthorize  做前置的权限判断

@Service
public class SecurityPermission {

    public boolean hasPermission(String id){
        return true;
    }

}
@RequiredArgsConstructor
@Service
public class UserService {

    @PreAuthorize("@securityPermission.hasPermission(#id)")
    public void create(String id){

    }

}
@Test
public void create(){
    JWTUserDetails userDetails =  JWTUserDetails.builder().token("").operateId(1L).build();
    Authentication authentication = new JWTAuthenticationToken(userDetails);
    SecurityContextHolder.getContext().setAuthentication(authentication);
    userService.create("1111");
}


hasPermission 的返回值是true,所以直接就过了,下面把返回值改成false,试试单元测试
org.springframework.security.access.AccessDeniedException: 不允许访问
spring security 提供的支持还不只这些,这里就不展开说,下回可以单独的篇幅专门讲。其实应用级别的,主要是需要一个方向或者思路,剩下的基本都可以通过查资料解决。

如果项目没有依赖spring security模块,那么我们还可以自己参考spring security自己实现

2.自己通过aop实现
写一个注解用于作为切面点

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface ActPermission {
    String value();
}


由于处理逻辑中需要对spel表达式支持,这里,定义一个 EvaluationContext

public class ActPermissionEvaluationContext extends MethodBasedEvaluationContext {
    public ActPermissionEvaluationContext(Object rootObject, Method method, Object[] arguments, ParameterNameDiscoverer parameterNameDiscoverer) {
        super(rootObject, method, arguments, parameterNameDiscoverer);
    }
}


具体实现逻辑

@Aspect
@Component
public class ActPermissionAspect implements ApplicationContextAware {

    private BeanResolver beanResolver;

    @Pointcut(value = "@annotation(ActPermission)")
    public void actPermissionAspect() {
    }

    @Before(value = "actPermissionAspect()")
    public void before(JoinPoint joinPoint){
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        ActPermission actPermission = AnnotationUtils.getAnnotation(methodSignature.getMethod(), ActPermission.class);
        if(Objects.isNull(actPermission)){
            return;
        }
        ExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new ActPermissionEvaluationContext(joinPoint, methodSignature.getMethod(), joinPoint.getArgs(),new DefaultParameterNameDiscoverer() );
        context.setBeanResolver(this.beanResolver);
        Boolean result = parser.parseExpression(actPermission.value()).getValue(context,Boolean.class);
        if(Objects.isNull(result) || !result){
            throw new RuntimeException("has no permission");
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.beanResolver = new BeanFactoryResolver(applicationContext);
    }
}

用法跟@PreAuthorize基本类似,都是基于spel表达式实现的

@Service
public class ArticleService {

    @ActPermission("@articleService.hasPermission(#id)")
    public void updateArticle(String id){
        System.out.println("update success");
    }

    public boolean hasPermission(String id){
        return false;
    }
}


自定义注解中的spel表达式,内容无法自动补全高亮,找了很久也没找到解决办法。有大佬知道,请指点指点。

spring
权限控制

关于作者

落雁沙
非典型码农
获得点赞
文章被阅读