水平越权的常见解决方法

场景模拟

  • 场景一

    只允许资源的所有者才能对资源进行操作(CRUD)。比如,jack在某博客平台写了一篇私密文章,只有自己可以对这篇文章进行增删查改的操作;

  • 场景二

    允许指定个人或者角色也能对资源进行操作。比如,jack邀请他的好朋友mason对文章进行查看和修改;

方案一

最简单和最直接的就是,在web层接收到操作请求后,在执行这个操作前,对请求的合法性进行校验。比如,查询当前需要操作的资源是否归属当前session中的已登录用户;或者查询当前需要操作的资源是否是允许操作的其它用户。

String loginUser = session.get("username");
// 增加水平越权校验
if(!checkAuthority(loginUser,articleId)){
  return false;
}
// 执行正常的操作
// 当前登录者是否是资源的所有者
private Boolean checkAuthority(String loginUser, String articleId){
  String articleOwner = articleService.getOwner(articleId);
  return Objects.equals(loginUser, articleOwner);
}
// 当前登录者是否有操作权限
private Boolean checkAuthority(String loginUser, String articleId){
  int count = articleService.getLegalUser(loginUser, articleId);
  return count > 0 ? Boolean.TRUE : Boolean.FALSE;
}

这种方案的优点是实现简单,逻辑清晰;但是缺点也很明显,需要对每一个请求都加上这种操作,很是繁琐,而且多了一次数据库查询,效率肯定有所下降;

方案二

我们可以直接将登录者的信息传递到SQL层面进行校验,比如场景一我们可以在原SQL最后加上一句来限制资源的操作。

select * from artile where article_id = #{articleId}
and author = #{loginUser}

如果是场景二的话,我们需要多关联一张表。

select * from artile a join author_guest g on a.author = g.author where article_id = #{articleId}
and g.guest = #{loginUser}

其中author_guest存放的是作者邀请的朋友之间的关系映射表。

这种方案的优点是没有增加额外的Java代码,没有增加额外的数据库查询,比较简洁优雅;但是缺点是需要改动SQL,增加了SQL的复杂性,而且有时一个SQL是供多块逻辑共用的,A模块需要鉴权,B模块不需要鉴权,那就要重新写一份相同的SQL或者在SQL上加分支了,那SQL会变得更难以理解和维护。

除此之外,好像还没法区分没有数据没有权限两种操作异常情况,只能给前端反馈操作异常的提示,不是很友好。

参考文章

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一. Java基础部分.................................................
    wy_sure阅读 3,832评论 0 11
  • API定义规范 本规范设计基于如下使用场景: 请求频率不是非常高:如果产品的使用周期内请求频率非常高,建议使用双通...
    有涯逐无涯阅读 2,582评论 0 6
  • 1.JVM 堆内存和非堆内存 堆和非堆内存按照官方的说法:“Java 虚拟机具有一个堆(Heap),堆是运行时数据...
    yanzhu728阅读 927评论 0 0
  • 业务处理层.h //分享单例对象 + (instancetype)shareLoadData; //获取数据 - ...
    法库德阅读 341评论 0 0
  • 循环结构的种类 顺序结构 选择结构 循环结构 顺序结构 从上到下依次执行 选择结构 if条件循环 三种格式第一种格...
    AuglyXu阅读 482评论 0 0