当前位置: 首页 > 科技观察

SpringSecurity内置的过滤器是如何维护的

时间:2023-03-17 01:31:38 科技观察

SpringSecurity中内置的过滤器顺序是如何维护的?我想很多开发者都对这个问题很感兴趣。在本文中,我将与您讨论这个问题。HttpSecurity包含一个成员变量FilterOrderRegistration,这个类是一个内置的过滤器注册表。至于这些过滤器的作用,不是本文的重点。有兴趣的可以查看FilterOrderRegistration的源码。内置过滤器FilterOrderRegistration的顺序维护了一个变量filterToOrder,它记录了类之间的顺序以及top和bottom之间的间隔步长。我们复制了一个FilterOrderRegistration来直观感受过滤器的顺序:CopyFilterOrderRegistrationfilterOrderRegistration=newCopyFilterOrderRegistration();//此方法不提供内置过滤器MapfilterToOrder=filterOrderRegistration.getFilterToOrder();TreeMaporderToFilter=newTreeMap<>();filterToOrder.forEach((名称,顺序)->orderToFilter.put(顺序,名称));orderToFilter.forEach((order,name)->System.out.println("Order:"+order+"类名:"+name));打印结果:我们可以看到内置过滤器之间的位置是比较固定的,除了第一步和第二步是200,其他步都是100。内置过滤器不一定生效,但是他们的排名是预设的需要通过HttpSecurity的addFilterXXXX系列方法显式添加。注册过滤器的逻辑FilterOrderRegistration提供了一个put方法:voidput(Classfilter,intposition){StringclassName=filter.getName();//如果这个类已经被注册,忽略if(this.filterToOrder.containsKey(className)){return;}//如果没有注册则注册序列。this.filterToOrder.put(className,position);}通过这个方法,我们可以得出几个结论:内置的34个过滤器的序号是固定的,不能更改。新添加的过滤器的完全限定类名不能与内置过滤器重复。新添加的过滤器的顺序可以与内置过滤器的顺序重复。获取注册过滤器的顺序值FilterOrderRegistration也提供了getOrder方法:IntegergetOrder(Classclazz){//如果类Class或父类Class名称为空,返回nullwhile(clazz!=null){整数结果=this.filterToOrder.get(clazz.getName());//如果获取到订单值,则返回if(result!=null){returnresult;}//否则,尝试获取父类的order值clazz=clazz.getSuperclass();}返回空值;}HttpSecurity维护过滤器的方法接下来我们分析一下HttpSecurity维护过滤器的几种方法。addFilterAtOffsetOfaddFilterAtOffsetOf是HttpSecurity内置的私有方法。Filter是要注册到DefaultSecurityFilterChain中的过滤器,offset是向右的偏移值,registeredFilter是已经注册到FilterOrderRegistration的过滤器,如果registeredFilter没有注册,就是一个空指针。privateHttpSecurityaddFilterAtOffsetOf(Filterfilter,intoffset,ClassregisteredFilter){//首先会根据registeredFilter的顺序和offset值计算过滤器的int顺序=this.filterOrders.getOrder(registeredFilter)+偏移量;//将过滤器添加到待排序的集合中this.filters.add(newOrderedFilter(filter,order));//过滤器注册到FilterOrderRegistrationthis.filterOrders.put(filter.getClass(),order);归还这个;}一定要记住registeredFilter必须是已经在FilterOrderRegistration中注册过的Filter。这里的addFilter系列方法以addFilterAfter为例。@OverridepublicHttpSecurityaddFilterAfter(Filterfilter,ClassafterFilter){returnaddFilterAtOffsetOf(filter,1,afterFilter);}addFilterAfter就是把filter的位置放在afterFilter之后一位。如果afterFilter的sequence值为400,那么filterorder值为401。addFilterBefore和addFilterAt逻辑与addFilterAfter的区别只是偏移值,这里不再赘述。addFilter的方法比较特殊:@OverridepublicHttpSecurityaddFilter(Filterfilter){Integerorder=this.filterOrders.getOrder(filter.getClass());if(order==null){thrownewIllegalArgumentException("过滤器类"+filter.getClass().getName()+"没有注册的顺序,没有指定的顺序不能添加。考虑使用addFilterBefore或addFilterAfter代替”);}this.filters.add(newOrderedFilter(filter,order));归还这个;filter必须是已经注册到FilterOrderRegistration的Filter,也就是说它可能是内置的Filter,也可能是之前通过addFilterBefore、addFilterAt或addFilterAfter注册的非内置Filter。在问题来之前,我看到了一个问题。如果HttpSecurity注册了两个序列号重复的Filter,顺序是怎样的?我们先看看排序机制://filtersprivateListfilters=newArrayList<>();//排序this.filters.sort(OrderComparator.INSTANCE);看OrderComparator的源码,其实还是通过数字的自然排序,数字越小越靠前。如果数字相同,则指数越小,越靠前。也就是说,相同的序号,谁先加入过滤器,谁就排在前面。