使用jfinal的Handler实现图片防盗链功能

JFinal大牛的干货分享,和我一样的小白们,快搬小板凳来向这里看齐~~~
 
第一步:新建一个Handler,用于拦截所有的图片资源请求,通过判断图片资源的请求来源,来分辨该请求是否来源于本站,如果不是来源于本站的请求,那么就返回一个默认的图片。
 
public class PicHandler extends Handler {
 
 
 @Override
 public void handle(String target, HttpServletRequest request,HttpServletResponse response, boolean[] isHandled) {
	
    String ctx = WebContextUtil.getContextPath(request); //获取网站的根路径
		
    String uri = request.getRequestURI();  //获取请求的uri
		
    if (uri.contains(".jpg") || uri.contains(".jpeg") || uri.contains(".png") || uri.contains(".gif")) {
		
	 //获取图片请求的来源地址,如果是直接在浏览器中输入图片地址请求的,返回null;如果是来源于本站的,会返回当前页面的地址;如果来源于外部网站,会返回外部网站的url地址。
	 String referer = request.getHeader("referer"); 
			
	 if (StrKit.notBlank(referer) && !referer.contains(ctx)) {
		 //如果不为空,且请求的来源地址里面不包含本站域名,那么说明就是通过外部网站请求的,图片外部网站被请求使用。
		 try {
			 //将请求转发掉,转发出一个根目录images文件夹下的一个默认图:guardAgainst.png,这样所有外站引用的图片,就全部都返回guardAgainst.png这张图片了。
			 request.getRequestDispatcher("/images/guardAgainst.png").forward(request, response); 
					
			 //不再让tomcat或者jetty处理该请求
			 isHandled[0] = true ; 
					
		 } catch (ServletException e) {
			 e.printStackTrace();
		 } catch (IOException e) {
			 e.printStackTrace();
		 }
	 }else {			     
		 next.handle(target, request, response, isHandled);
	 }
   }else {
	 next.handle(target, request, response, isHandled);
   }
 }
}
 
特别注意,else里面的next.handle(target, request, response, isHandled);  一定要写到else里面,当图片请求来源是本站时,不转发请求,将请求交给jFinal处理。只有不是本站的请求的时候,才进行请求转发,在请求转发以后, writer 关闭 ,所以不可以再讲请求交给jfinal或者tomcat/jetty处理,否则会抛出java.lang.IllegalStateException: Committed 的异常。
 
 
第二步:在配置中配置这个Handler。
 
public class SystemConfig extends JFinalConfig {
 
    public void configHandler(Handlers me) {
	 me.add(new PicHandler()); //配置图片资源的Handler
    }
}
 
另附一个上面用到的小工具类:
public class WebContextUtil {
        /**
	 * 获取上下文URL全路径
	 * @param request
	 * @author nbjgl
	 */
 public static String getContextPath(HttpServletRequest request) {
     StringBuilder sb = new StringBuilder();
     int port = request.getServerPort();
     if(80==port){
	 sb.append(request.getScheme()).append("://").append(request.getServerName()).append(request.getContextPath());
     }else{
	 sb.append(request.getScheme()).append("://").append(request.getServerName()).append(":").append(port).append(request.getContextPath());
     }
 
	 String path = sb.toString();
	 return path;
   }
}


评论区

JFinal

2016-10-12 20:55

对图片后缀的判断可以预先将所有要控制的后缀放在一个 HashSet 中,然后用下面一句就可以判断了:
if (picSet.contains(...))
是需要控制的图片

JFinal

2016-10-12 20:55

感谢分享

七五热

2016-10-13 16:31

6666受教@jfinal抓紧写入文档啊,菜鸟都不会

百万

2018-02-12 15:28

这段逻辑有问题,StrKit.notBlank(referer) && !referer.contains(ctx),假如refer为null,就会直接执行else里的next

欲风217

2018-05-28 21:13

我在 abc.com 站点中加入防盗链的 handler,在 abc.com 站点中加入 img 标签,会进入 handler,referer 是 null。后在 xyz.com 站点中加入 img 标签,并没有进入到 abc.com 的防盗链 handler 中。这是为何?@JFinal @nbjgl

热门分享

扫码入社