手记

记一次协助排查权限问题的经历

  这个事情其实对于每一位后端来讲都是很稀松平常的事情,但可能笔者这块经历较少的缘故,觉得还是比较有意思的,就当做一次备忘录吧。

  由于公司在某个项目的权限表的树层级因定制化缘故做了调整,但权限表调整之后,测试发现,新建用户时,勾选某几个权限后,发现作为菜单的一级权限没有问题,但其他的诸如页面中的权限都失效了,而测试起初测出的结果是某个模块失效,这块的界面出不来,甚至都没联想到是权限的缘故(这个模块的非菜单类权限很多,甚至包括它本身页面的显示也是由权限控制的)。

  这时候需要排查原因,根据起初的结果,以为是某个模块的前端代码有问题,因为直观的显示就是界面出不来,然后就找了我,XXX,界面出不来啦,怎么搞?

  简略看了代码之后,没什么问题,服务器上的代码也没有问题,所以这时候基本可以排除前端的问题了。

  这时候想到的是权限的问题,可是,权限好端端的,怎么就出问题了呢?我新建了一个用户,很多权限都没问题,但到了上面所说的那个模块,出问题了,果然,出不来。再看返回权限ID的接口,果然,这个权限勾选后,没有。

  好了,问题模拟出来了,本来这个可以直接丢给后端,但抱着试一试的心态找找看,也就有了下面的思考。

  问题的排查过程:

  1、由于公司的接口都有一套特定的规范,所以很好找,找到这个接口的.java文件,根据特定的类规则,找到dao层的SQL,比较幸运的是这个项目的SQL就是字符串拼接,可以直接拿到navcat里执行,这样我拿到了这样的一串SQL。

select DISTINCT FUN_CODE, MENUID, URL from SYS_FUNLIST s, SYS_USERFUNC u where s.FUN_CODE = u.ORG_CODE and u.USER_CODE = 'test0'

  这串SQL的大意其实就是查询表SYS_FUNLIST中的三个字段,当这个表中的FUN_CODE这个字段的值等于另一张SYS_USERFUNC表的ORG_CODE字段的值时,将结果集过滤出来。

  也就是说用户的权限结果集实际上是一张总表中,根据另一张的用户关联表过滤出来的结果。而这条SQL的执行结果,与新建用户保存时前端传递的权限CODE不一致(出问题的模块前缀是12,而这里只查出了05)。而刚好出问题的那个模块,除了一个入口的菜单权限,其他都没有。

  2、这样问题就很明显了,新建用户时,有一部分的权限选择后无效,无效包括两种可能,存和取,也就是前端数据传递到了后端,但后端没正常保存到数据库,但过往的权限一直没有问题,那是不是取的问题?可是查询的SQL也一直没人动过,那会是什么问题导致的呢?我联想到了最近后端因项目需求调整过这张权限表的层级,那是不是这个导致的呢?

  3、问题的关键在于SYS_USERFUNC这张用户权限表,这张由于本人不是后端,起初也不明白做了啥事,但进去之后,发现里面就只有两个CODE值,一个用户的CODE,一个权限CODE,某个用户可能出现很多条这个用户对应的另一个CODE,这时候回头重新建一个用户,并勾上有问题模块的权限,从前端返回的数据来看,这个模块的权限CODE的前缀都是12******,再到用户权限表中查看,发现前端的CODE都正确插入进来了,既然存是没问题的,那问题就只剩下查了。

  4、将整张的SYS_FUNLIST权限菜单总表看了一遍,发现里面确实有这个12开头的权限,但不是FUN_CODE这个字段,而是另一个FUNID字段,可是为何原来的SQL会用这个字段来关联呢?原来,这个字段跟FUNID这个字段是一样的,只不过FUNID是主键,要在同一张表中分化出各种各样的权限树,需要有另一个具备主键唯一性的键,设计之初就增加了一个与之一致的字段,也就是FUN_CODE。

  5、而为什么会出现上面那个问题?原来,是因为调整了SYS_FUNLIST这张权限菜单总表层级时,不得不将这个FUN_CODE的code值改变,因为前面说的code前缀实际上代表着不同的模块,而出问题的那个模块,实际上就是另外的模块,这样虽然权限树是出来了,也正确保存到关联表中,但由于存进去的是FUNID,而拿来查的是FUN_CODE,而为了某一个定制做了表的调整,这两个字段值不一致了,就导致问题出来了。

  6、那是不是就很好解决了呢?是的,其中第一个方案就是将FUN_CODE的值重新调整成跟FUNID一样的值,但定制化的权限树就没用了,那怎么办呢?改SQL,也就是将上面的FUN_CODE换掉,改成用FUNID去查,也就是这样:

select DISTINCT FUNID, FUN_CODE, MENUID, URL from SYS_FUNLIST s, SYS_USERFUNC u where s.FUNID = u.ORG_CODE and u.USER_CODE = 'test0'

  这样,就能正常返回结果集,但由于整条主分支的缘故,不能因为某个定制化的项目影响到其他项目,所以最后的解决方案就是拉一个分支出来,打一个tag,原基线的东西不做变动,这样问题也就最终解决啦。

0人推荐
随时随地看视频
慕课网APP