最近在做API接口安全类似支付宝接口那种方式,为了对所有接口做一致性处理,准备使用拦截器方式在底层。Jersey有两种拦截器ContainerRequestFilter与ContainerResponseFilter,接口请求验证使用ContainerRequestFilter,具体实现代码如下
@Provider
public class SafeFilter implements ContainerRequestFilter{
@Context
private HttpServletRequest servletRequest;
@Context
private HttpServletResponse servletResponse;
private Logger safeLog=LoggerFactory.getLogger(VerifyFilter.class);
@SuppressWarnings("rawtypes")
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// TODO Auto-generated method stub
UriInfo urlInfo=requestContext.getUriInfo();
if(urlInfo.getPath().contains("v1/api/getappaccesstoekn")){
Enumeration<String> listParam=servletRequest.getParameterNames();
HashMap<String,String> map=new HashMap<String, String>();
String signStr="";
String timespan="0";
String deviceid="";
while(listParam.hasMoreElements()){
String name=(String)listParam.nextElement();
String value=servletRequest.getParameter(name);
if(name.equals("signStr")){
signStr=value;
}
else if(name.equals("timespan")){
timespan=value;
}
else if(name.equals("deviceid")){
deviceid=value;
}
else{
map.put(name, value);
}
}
//是否有这三个参数
String token= RedisService.getInstance().getAppImeiToken(deviceid);
if(TextUtil.isNullEmptyOrWhitespace(token)){
HashMap<String,Object> resultMap=new HashMap<String,Object>();
resultMap.put(RESULT, INVAILDEDTOKEN.getResultCode());
Response response = Response.ok(resultMap).status(200).type(MediaType.APPLICATION_JSON).build();
throw new WebApplicationException(response); // Throw new UnAuthorized
}
map.put("token", token);
long lCurTime=System.currentTimeMillis();
long lTimeSpan=Long.parseLong(timespan);
if(lCurTime-lTimeSpan>60000){
filterLog.info(ErrorMessage.VERIFY_TIMESTAP,servletRequest.getRequestURI());
}
SortedMap<String,String> sort=new TreeMap<String,String>(map);
Set es = sort.entrySet();
Iterator it = es.iterator();
StringBuilder sb=new StringBuilder();
while(it.hasNext()){
Map.Entry entry = (Map.Entry)it.next();
sb.append(entry.getValue());
System.out.println("排序之后:"+entry.getKey()+" 值"+entry.getValue());
}
try {
String okSignStr=MD5Util.md5Encode(sb.toString());
if(!okSignStr.equals(signStr)){
HashMap<String,Object> resultMap=new HashMap<String,Object>();
resultMap.put(RESULT, SIGNATUREINCONSISTENT.getResultCode());
Response response = Response.ok(resultMap).status(200).type(MediaType.APPLICATION_JSON).build();
throw new WebApplicationException(response); // Throw new UnAuthorized
}
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Jersey拦截器有@PreMatch @Provider注解,分别代表意思有请求匹配前和请求匹配后。实现好代码后需要在web.xml里面配置serverlet拦截器信息和拦截器类的包名具体如下
<init-param>
<param-name>javax.ws.rs.container.ContainerRequestFilter</param-name>
<param-value>pacages</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>pacages</param-value>
</init-param>
jersey官网文档