⚡️ 在开发钉钉机器人的时候,由于想要做权限控制,但是又不想做复杂,只想做一个轻量级的区分,于是搭了一个轻量级的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() {
// ...
}
}
⚡️这个就是我们的业务层设置的权限等级,配置的用户权限如果低的话,就没有权限访问