在开发中遇到一个场景,当需要提供接口给其他系统,并需要鉴权时,我当时的处理方案是用过滤器拦截进行个性化鉴权,如果鉴权通过则还是需要经过安全测试、转码等filter,但是不走后面的鉴权过滤器,不通过则跳转到错误页面。
这里就需要去掉过滤器链中的某一个过滤器,下面介绍下我的方案:通过反射修改过滤器链:
/**
*
* 通过反射修改过滤器链
* @param chain
*/
private void skipFilter(FilterChain chain) {
try {
//排除的过滤器数组
Object[] filterArr=new Object[]{InterfaceConstants.UN_AUTH_FILTER};
Field field = chain.getClass().getDeclaredField("filters");
field.setAccessible(true);
FilterConfig[] filters = (FilterConfig[]) field.get(chain);
int k = 0;
for (int i = 0; i < filters.length; i++) {
if (filters[i] != null) {
Field field2 = filters[i].getClass().getDeclaredField("filterDef");
field2.setAccessible(true);
Field field3 = field2.get(filters[i]).getClass().getDeclaredField("filterClass");
field3.setAccessible(true);
String filterClass = (String) field3.get(field2.get(filters[i]));
int loc = Arrays.binarySearch(filterArr, filterClass);
if (loc >= 0) {
//将过滤器重置为null
filters[i] = null;
k++;
}
field3.setAccessible(false);
field2.setAccessible(false);
}
}
int index = 0;
for (int i = 0; i < filters.length; i++) {
if (index == 0 && filters[i] == null) {
index = i;
} else if (index != 0 && filters[i] != null) {
filters[index] = filters[i];
filters[i] = null;
i = index;
index = 0;
}
}
field.setAccessible(false);
Field n=null;
try {
n = chain.getClass().getDeclaredField("n");
logger.info("tomcat容器中filter的n属性");
} catch (Exception e) {
n = chain.getClass().getDeclaredField("filterCount");
logger.info("jboss容器中filterCount属性");
}
if(n!=null){
n.setAccessible(true);
n.set(chain, n.getInt(chain) - k);
n.setAccessible(false);
}
} catch (Exception e) {
logger.error("通过反射修改过滤器链出错",e);
}
}