How to use the elegant cut and comment privileges achieve verification

background

Permission Validation in our system is a business logic has nothing to do but it is closely related to a business function.
We developed a vision for small and medium enterprises to customize the system's members. The system can provide services for enterprises A, B and other business enterprises. Database table structure is often so (the following is just a demo, the actual situation in the field will be more and more complex):

id memberCardCode userName card_status business
1 a564456578 zhangsan 0 business-a
2 b678688643 lysis 1 businsss-b
3 a775445667 wangwu 0 businsss-a
4 b943578978 zhaoliu 1 businsss-b
5 c657688799 sunqi 1 businsss-c

Based on the above table, we remove id = 1 members often this operation (assumed to be physically deleted):
the Controller layer:

@RestController("/member")
public class MemberController {
    @PostMapping("/delete")
    public void deleteById(int id) {
        // 此处省略删除代码
    }
}
复制代码

SQL statement in final call in the controller like this:

delete from member where id = 1;
复制代码

At first glance, it is such a simple sql statement to have any problem then? In fact, the more simple question, the more can not let go.
By the table, we see membership information id = 1 belongs to the business-a. It is supposed to be business-a account you can delete the membership information id = 1. That time if business-b delete members when the id parameter to 1, then there will be business-b deleted the members of business-a. At this time, the business-a mood crash.

So it is necessary to verify permission. That authority verify how to do it?

Inelegant: invasive business code scheme

In the controller layer was added logical judgment: to determine whether to delete the current account id, if they are then deleted; otherwise return directly. code show as below:

@RestController("/member")
public class MemberController {
    @PostMapping("/delete")
    public void deleteById(int id) {
        // 第一步:权限验证
        Integer id = selectByIdAndBusiness(id, "business-a");
        if (id == null) {
            // 说明id不属于business-a不能删除
            return;
        }
        // 第二步:调用删除逻辑
    }
}
复制代码

The above code does solve the problem of ultra vires, but some business will be independent of the code to invade our business logic, this logic is unlikely to achieve elegance. Then we choose a more elegant way to verify the complete authority.

Elegant: + Notes section of the program

First we need to clear the field of information concern: id and business. Where business can be stored in a ThreadLocal filter in, so we just need to focus on field id.
Step 1: Create custom annotation (method acting)

@Documented  
@Retention(RetentionPolicy.RUNTIME)  
@Target(ElementType.METHOD)  
public @interface Auth {
    // 方法的参数名称,以防参数名称不是id,所以提供paramName
    String paramName() default "id";
}
复制代码

Step 2: Use annotations on the method

package com.demo.controller;
@RestController("/member")
public class MemberController {
    @PostMapping("/delete")
    @Auth(paramId = "deleteId")
    public void deleteById(int deleteId) {
        // 调用删除逻辑
    }
}
复制代码

The third step: implement the aspect

// 通过注解可以看到,我们该方法切的是controller层带有Auth注解的方法
@Before(value = "execution(public * com.demo.controller..*.*(..))"
      + " && @annotation(auth)", argNames = "pjp, auth")
public void before4Auth(JoinPoint pjp, Auth auth) {
    // 1、通过ThreadLocal获取business
    String business = context.get();
    // 2、通过注解解析id
    // 2.1 获取参数值
    Object[] args = pjp.getArgs();
    // 2.2 获取参数名
    MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
    String[] parameterNames = methodSignature.getParameterNames();
    // 2.3 获取注解中paramName的下标
    int index = ArrayUtils.indexOf(parameterNames, auth.paramName());
    // 2.4 根据下标获取id对应的值
    int val = (int) args[index];
    // 2.5 鉴权逻辑
    Integer id = selectByIdAndBusiness(val, business);
    if (id == null) {
        // 抛异常提示越权
    }
    // 否则的正常执行下面的业务逻辑
}
复制代码

In this way, we simply method layer controller plus @Authannotations can be. No trespassing non-business code, implementation can be considered elegant.
If you have a more elegant solution, welcome ideas.

Guess you like

Origin juejin.im/post/5d79f66f6fb9a06af13d96d0