一、前言
通过javax.servlet.Filter过滤器自定义LoginFilter登录授权过滤器类,并通过定义Processor处理上下文接口、AbstractProcessor抽象类、处理接口返回类型ProcessorResult枚举类,实现用户登录过程中的XSS攻击安全过滤、访问控制限制处理、登录字段验证类、session会话刷新、超时验证等逻辑处理单元等。
二、代码示例
1. Processor接口、AbstractProcessor抽象类、ProcessorContext上下类
public interface Processor {@b@@b@ ProcessorResult process(ProcessorContext context);@b@ @b@}
public abstract class AbstractProcessor implements Processor {@b@@b@ @Override@b@ public ProcessorResult process(ProcessorContext context) {@b@ ProcessorResult result = ProcessorResult.CONTINUE;@b@ @b@ try{@b@ ProcessorResult tempResult = this.doProcess(context);@b@ result = (tempResult == null ? result : tempResult);@b@ } catch(Exception e) {@b@ result = ProcessorResult.REJECT;@b@ }@b@ @b@ return result;@b@ }@b@ @b@ public abstract ProcessorResult doProcess(ProcessorContext context);@b@@b@}
public enum ProcessorResult {@b@@b@ REJECT("reject"), COMPLETE("complete"), CONTINUE("continue");@b@ @b@ private String message;@b@ @b@ private ProcessorResult(String message){@b@ this.message = message;@b@ }@b@@b@ public String getMessage() {@b@ return message;@b@ }@b@}
import java.util.Map;@b@import java.util.concurrent.ConcurrentHashMap;@b@@b@public class ProcessorContext {@b@@b@ private Map<String, Object> context = new ConcurrentHashMap<String, Object>();@b@@b@ public void put(String key, Object value) {@b@ if (key != null && value != null) {@b@ this.context.put(key, value);@b@ }@b@ }@b@@b@ public Object get(String key) {@b@ return this.context.get(key);@b@ }@b@@b@ @SuppressWarnings("unchecked")@b@ public <T> T getValue(String key) {@b@ Object obj = this.context.get(key);@b@ if (obj == null) {@b@ return null;@b@ }@b@ return (T) obj;@b@ }@b@@b@ public boolean getBooleanValue(String key) {@b@ Boolean value = getValue(key);@b@ if (value == null) {@b@ return false;@b@ }@b@ return value;@b@ }@b@@b@ public Object remove(String key) {@b@ return this.context.remove(key);@b@ }@b@@b@ @SuppressWarnings("unchecked")@b@ public <T> T removeValue(String key) {@b@ Object obj = this.context.remove(key);@b@ if (obj == null) {@b@ return null;@b@ }@b@ return (T) obj;@b@ }@b@ @b@ public void clear() {@b@ this.context.clear();@b@ }@b@@b@ public boolean isValid() {@b@ if (this.context != null && !this.context.isEmpty()) {@b@ return true;@b@ } else {@b@ return false;@b@ }@b@ }@b@ @b@ public boolean contains(String key){@b@ return context.containsKey(key);@b@ }@b@}
2. ProcessorChain实现类
import java.util.ArrayList;@b@import java.util.List; @b@import org.apache.commons.lang.Validate;@b@import org.apache.commons.lang.builder.ToStringBuilder;@b@import org.apache.commons.lang.builder.ToStringStyle;@b@import org.apache.log4j.Logger; @b@import com.xwood.mobilegw.util.LoggerUtil;@b@ @b@public class ProcessorChain implements Processor {@b@ @b@ private static final Logger logger = Logger@b@ .getLogger(ProcessorChain.class);@b@ @b@ private List<Processor> processorList = new ArrayList<Processor>();@b@@b@ @Override@b@ public ProcessorResult process(ProcessorContext context) {@b@ ProcessorResult result = ProcessorResult.COMPLETE;@b@ @b@ for (Processor processor : processorList){@b@ result = processor.process(context);@b@ //printLog(processor, context, result);@b@ @b@ if (!result.equals(ProcessorResult.CONTINUE)){@b@ return result;@b@ }@b@ }@b@ @b@ return result;@b@ }@b@ @b@ public void add(Processor processor){@b@ Validate.notNull(processor, "processor can not be null!");@b@ this.processorList.add(processor);@b@ }@b@ @b@ public void add(Processor... processors){@b@ Validate.notNull(processors, "processors can not be null!");@b@ for(Processor processor : processors){@b@ this.processorList.add(processor);@b@ }@b@ }@b@@b@ public List<Processor> getProcessorList() {@b@ return processorList;@b@ }@b@@b@ public void setProcessorList(List<Processor> processorList) {@b@ this.processorList = processorList;@b@ }@b@ @b@ private void printLog(Processor processor, ProcessorContext context, ProcessorResult result){@b@ String className = processor.getClass().getSimpleName();@b@ String parameters = ToStringBuilder.reflectionToString(context, ToStringStyle.SIMPLE_STYLE);@b@ @b@ StringBuilder builder = new StringBuilder();@b@ builder.append("处理的节点为: ");@b@ builder.append(className);@b@ @b@ builder.append(";\t");@b@ builder.append("参数为: ");@b@ builder.append(parameters);@b@ @b@ builder.append(";\t");@b@ builder.append("结果为: ");@b@ builder.append(result.name());@b@ @b@ LoggerUtil.info(logger, builder.toString());@b@ }@b@ @b@}
import javax.servlet.http.HttpServletRequest; @b@import com.xwood.mobilegw.bo.CustomerBO;@b@import com.xwood.mobilegw.bo.CustomerDynamicBO;@b@import com.xwood.mobilegw.util.customer.LoginUtil;@b@import com.xwood.mobilegw.util.processorchain.AbstractProcessor;@b@import com.xwood.mobilegw.util.processorchain.ProcessorConst;@b@import com.xwood.mobilegw.util.processorchain.ProcessorContext;@b@import com.xwood.mobilegw.util.processorchain.ProcessorResult;@b@@b@ @b@public class SessionRefreshProcessor extends AbstractProcessor{@b@ @b@ @Override@b@ public ProcessorResult doProcess(ProcessorContext context) { @b@ @b@ HttpServletRequest httpRequest = context.getValue(ProcessorConst.HTTPREQUEST);@b@ CustomerBO customerBO = context.getValue(ProcessorConst.CUSTOMERBO);@b@ CustomerDynamicBO dynamicBO = context.getValue(ProcessorConst.DYNAMICBO);@b@ @b@ LoginUtil.putCustomerInfoToSession(httpRequest, customerBO, dynamicBO);@b@ @b@ return ProcessorResult.COMPLETE;@b@ }@b@}
3. LoginFilter处理规则主类
package com.xwood.mobilegw.web.filter;@b@@b@import java.io.IOException;@b@import javax.servlet.Filter;@b@import javax.servlet.FilterChain;@b@import javax.servlet.FilterConfig;@b@import javax.servlet.ServletException;@b@import javax.servlet.ServletRequest;@b@import javax.servlet.ServletResponse;@b@import javax.servlet.http.HttpServletRequest;@b@import javax.servlet.http.HttpServletResponse;@b@import org.apache.commons.lang.StringUtils;@b@import org.apache.log4j.Logger;@b@import com.alibaba.fastjson.JSON;@b@import com.alibaba.fastjson.JSONArray;@b@import com.alibaba.fastjson.JSONObject;@b@import com.xwood.mobilegw.adapterservice.ResultEnum;@b@import com.xwood.mobilegw.biz.login.processorchain.AccessLimitProcessor;@b@import com.xwood.mobilegw.biz.login.processorchain.AnyDoorTicketRefreshProcessor;@b@import com.xwood.mobilegw.biz.login.processorchain.DynamicInfoUpdateProcessor;@b@import com.xwood.mobilegw.biz.login.processorchain.LoginValidationProcessor;@b@import com.xwood.mobilegw.biz.login.processorchain.ReLoginProcessor;@b@import com.xwood.mobilegw.biz.login.processorchain.ServiceConfigValidator;@b@import com.xwood.mobilegw.biz.login.processorchain.SessionRefreshProcessor;@b@import com.xwood.mobilegw.biz.login.processorchain.SessionValidationProcessor;@b@import com.xwood.mobilegw.biz.login.processorchain.TimeoutValidationProcessor;@b@import com.xwood.mobilegw.biz.login.processorchain.XssAttackProcessor;@b@import com.xwood.mobilegw.bo.CustomerBO;@b@import com.xwood.mobilegw.bo.CustomerDynamicBO;@b@import com.xwood.mobilegw.core.model.GatewayResponse;@b@import com.xwood.mobilegw.core.service.util.ResponseUtil;@b@import com.xwood.mobilegw.util.LoggerUtil;@b@import com.xwood.mobilegw.util.customer.CustomerUtil;@b@import com.xwood.mobilegw.util.processorchain.Processor;@b@import com.xwood.mobilegw.util.processorchain.ProcessorChain;@b@import com.xwood.mobilegw.util.processorchain.ProcessorConst;@b@import com.xwood.mobilegw.util.processorchain.ProcessorContext;@b@import com.xwood.mobilegw.util.processorchain.ProcessorResult;@b@import com.xwood.mobilegw.util.processorchain.ProcessorUtil;@b@@b@public class LoginFilter implements Filter {@b@@b@ private static final Logger logger = Logger.getLogger(LoginFilter.class);@b@@b@ private ProcessorChain loginChain = new ProcessorChain();@b@@b@ @Override@b@ public void init(FilterConfig filterConfig) throws ServletException {@b@ loginChain.add(new XssAttackProcessor()); *//** 防止XSS处理的过滤器*//*@b@ loginChain.add(new ServiceConfigValidator());@b@ loginChain.add(new AccessLimitProcessor());@b@ loginChain.add(new LoginValidationProcessor());@b@ loginChain.add(new SessionValidationProcessor());@b@ loginChain.add(new TimeoutValidationProcessor());@b@ loginChain.add(new ReLoginProcessor());@b@ loginChain.add(new DynamicInfoUpdateProcessor());@b@ loginChain.add(new SessionRefreshProcessor());@b@ }@b@@b@ @Override@b@ public void doFilter(ServletRequest request, ServletResponse response,@b@ FilterChain filterChain) throws IOException, ServletException {@b@ ProcessorContext context = initProcessorContext(request, response);@b@ if (!context.isValid()) {@b@ LoggerUtil.info(logger, "LoginFilter初始化参数失败");@b@ return;@b@ }@b@@b@// ProcessorResult result = loginChain.process(context);@b@ @b@ /**api debug switcher*/@b@ ProcessorResult result=ProcessorResult.COMPLETE;@b@ @b@ @b@ switch (result) {@b@ case REJECT:@b@ return;@b@@b@ case COMPLETE:@b@ filterChain.doFilter(request, response);@b@ break;@b@@b@ default:@b@ LoggerUtil.error(logger, null, "LoginFilter处理异常");@b@ break;@b@ }@b@ }@b@@b@ @Override@b@ public void destroy() {@b@@b@ }@b@@b@ private ProcessorContext initProcessorContext(ServletRequest request,@b@ ServletResponse response) {@b@@b@ ProcessorContext context = new ProcessorContext();@b@@b@ HttpServletRequest httpRequest = (HttpServletRequest) request;@b@ HttpServletResponse httpResponse = (HttpServletResponse) response;@b@ String operationType = null;@b@ String requestData = null;@b@@b@ try {@b@ operationType = (String) httpRequest.getParameter("operationType");@b@ requestData = (String) httpRequest.getParameter("requestData");@b@@b@ JSONArray dataArray = JSON.parseArray(requestData);@b@ JSONObject dynamicInfo = dataArray.getJSONObject(0);@b@@b@ CustomerDynamicBO dynamicBO = CustomerUtil.wrapCustomerDynamicBo(@b@ dynamicInfo, httpRequest);@b@ CustomerBO customerBO = null;@b@@b@ if (StringUtils.isNotEmpty(dynamicBO.getSessionId())) {@b@ customerBO = CustomerUtil.getCustomerBoBySession(dynamicBO@b@ .getSessionId());@b@ }@b@@b@ context.put(ProcessorConst.REQUESTDATA, requestData);@b@ context.put(ProcessorConst.CUSTOMERBO, customerBO);@b@ context.put(ProcessorConst.DYNAMICBO, dynamicBO);@b@ context.put(ProcessorConst.HTTPREQUEST, httpRequest);@b@ context.put(ProcessorConst.HTTPRESPONSE, httpResponse);@b@ } catch (Exception e) {@b@ LoggerUtil.error(logger, e, "参数验证不合法, operationType = ",@b@ operationType, ", requestData = ", requestData);@b@ GatewayResponse gatewayResponse = ResponseUtil.buildErrorResponse(ResultEnum.ValueInvalid);@b@ ProcessorUtil.buildAPPResponse(gatewayResponse, httpRequest, httpResponse);@b@ context.clear();@b@ }@b@@b@ return context;@b@ }@b@}