基于AOP和自定义注解实现的接口权限管理

⚡️ 在开发钉钉机器人的时候,由于想要做权限控制,但是又不想做复杂,只想做一个轻量级的区分,于是搭了一个轻量级的Demo
⚡️ 实现思路:对用户的唯一标识进行权限等级的设置,并将请求等级放在线程的上下文当中,请求接口的时候,通过动态代理判断用户的接口权限
⚡️部分代码已经隐藏了哈~

SQL

create table xxxx.t_robot_authority
(
    id  bigint auto_increment  primary key,
    user_id   varchar(100)  not null comment '唯一标识',
    level     int default 0 null comment '权限等级',
    nick_name varchar(20)   null comment '名称'
)
    comment 'xxxxxx权限配置';

存储上下文消息,用于接口鉴权

/**
 * 会话上下文
 * @author Cocowwy
 * @create 2021-11-11-11:04
 */
@Data
@Builder
public class MessageContext {
    // 钉钉唯一标识
    private String userId;

    // 钉钉展示名
    private String nickName;

    // 权限开放等级
    private Integer level;
}

/**
 * @author Cocowwy
 * @create 2021-11-11-12:33
 */
public class MessageContextHolder {
    private static final ThreadLocal<MessageContext> THREAD_LOCAL = new NamedThreadLocal<>("messageContext");

    private MessageContextHolder() {
    }

    public static MessageContext current() {
        return THREAD_LOCAL.get();
    }

    public static void clean() {
        THREAD_LOCAL.remove();
    }

    public static void set(MessageContext messageContext) {
        THREAD_LOCAL.set(messageContext);
    }
}

统一入口处设置权限等级

    @PostMapping("/message")
    public String message(@RequestBody(required = true) JSONObject json) {
        log.info("---------->> text:{}", json);
        String message = json.getJSONObject("text").toJSONString();
        RobotAuthority user = robotAuthorityRepository.queryByUserId(String.valueOf(json.get("senderId")));
        MessageContext context = MessageContext.builder()
                .nickName(String.valueOf(json.get("senderNick")))
                .userId(String.valueOf(json.get("senderId")))
                .level(user == null ? 0 : user.getLevel())
                .build();
        MessageContextHolder.set(context);

⚡️这里由于方便,博主使用的是SpringData-JDBC用作持久层,可以理解成权限等级配置在上表当中,在入口处/过滤器当中向上下文中设置了权限(因为博主的demo只有一个请求,所以写在了controller,这里建议将这块方法移动到过滤器当中然后设置上下文)

AOP(切面层)对业务接口进行权限控制~

/**
 * 基于服务层的权限切面
 * @author Cocowwy
 * @create 2021-11-11-13:59
 */
@Aspect
@Component
@Slf4j
public class AuthorityAspect {

    /**
     * 对接口进行权限校验
     */
    @Pointcut("execution(public * com.cocowwy.cn.service.impl.xxxxxxx.*(..))")
    private void pointcut() {
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        int level = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(AuthorityLevel.class).value();
        if (MessageContextHolder.current().getLevel() < level) {
            return Result.error("木有权限执行此操作嗷~");
        }
        Object proceed = joinPoint.proceed();
        return proceed;
    }
}

⚡️在这里做的权限的等级判断,当然,这里得注解是自定义的,同时接口方法上需要标记上权限等级,如下~

权限注解

/**
 * @author Cocowwy
 * @create 2021-11-11-14:08
 */
@Target(ElementType.METHOD)
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthorityLevel {
    // 权限等级默认为0
    int value() default 0;
}

设置该方法的权限,即配置的用户权限大于所配置的时候,才可调用该接口

/**
 * @author Cocowwy
 * @create 2021-10-10-11:03
 */
@Service
public class CommandServiceImpl implements CommandService {
    @Autowired
    private TakeoutClient takeoutClient;

    @Override
    @AuthorityLevel(9)
    public XXX a() {
      // ....
    }
    
    @SneakyThrows
    @Override
    @AuthorityLevel(9)
    public XXX b() {
  		// ...
    }
}

⚡️这个就是我们的业务层设置的权限等级,配置的用户权限如果低的话,就没有权限访问

你可能感兴趣的:(springboot,中间件等,shiro,三方对接,spring,boot,spring)