package com.kingschan.blog.web.interceptor; import java.io.IOException; import java.net.URLDecoder; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.annotation.Resource; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.kingschan.blog.services.system.impl.UrlValidationServiceImpl; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import com.kingschan.blog.common.enums.BLOG_MODEL; import com.kingschan.blog.common.enums.Variable; import com.kingschan.blog.common.freemarker.util.TemplateStaticUtil; import com.kingschan.blog.common.skin.template.SkinTemplateVariable; import com.kingschan.blog.model.vo.UserVo; import com.kingschan.blog.po.User; import com.kingschan.blog.po.WebSite; import com.kingschan.blog.services.ArticleService; import com.kingschan.blog.services.WebSiteService; import com.kingschan.blog.services.impl.CommonServiceImpl; import com.kingschan.blog.util.BlogUrlHelper; import com.kingschan.blog.util.BlogUtil; /** * 博客系统url映射跳转核心过滤器 * @author kings.chan * */ @Component("BlogFilter") public class BlogFilter implements Filter{ @Autowired private WebSiteService websiteServ; @Autowired private ArticleService articleServ; @Resource(name="CommonServiceImpl") private CommonServiceImpl commonServ; @Autowired private UrlValidationServiceImpl urlValidateServ; //默认跳转博客 @Value("${app.default.blog.keyword}") private String defaultBolg; @Autowired private TemplateStaticUtil tsu; //runtime declare private String blogname;//当前博客名 @Value("${sina_weibo_login_url}") private String sinaWeiBoLoginUrl; @Autowired private SkinTemplateVariable skinVariable; private static Logger log = LoggerFactory.getLogger(BlogFilter.class); @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req=(HttpServletRequest) request; HttpServletResponse rep=(HttpServletResponse) response; String url= req.getRequestURI(); long start_time=System.currentTimeMillis(); String referer =req.getHeader("referer"); String agent=req.getHeader("User-Agent"); BlogUtil bu =new BlogUtil(req); try { if (url.matches(".*\\.php")) { rep.sendError(403); return; }else if (url.matches("^/www/.*")) { if (commonServ.isDebug()) { log.debug("静态资源直接返回{}",req.getRequestURL()); } chain.doFilter(request, response);//静态资源直接返回 return; }else if (StringUtils.isEmpty(agent)) { rep.sendError(403);//拒绝非浏览器访问 return; } filter(req, rep, request, response, chain, url, bu, referer); String req_blog=null==blogname?"51so":blogname; String req_url=URLDecoder.decode(url, "UTF-8"); if (rep.getStatus()==HttpServletResponse.SC_NOT_FOUND||rep.getStatus()!=200) { log.error( "[{}] url:{} furl:{} referer:{} user-agent:{} ip:{} run {} millis .", rep.getStatus(), req_url, URLDecoder.decode(req.getRequestURL().toString(), "UTF-8"), referer,req.getHeader("User-Agent"), req.getRemoteAddr(), System.currentTimeMillis()-start_time ); return; //不记录不存在的链接 } else if (url.matches("^/[admin|pub|font]+.*")) { return ;//不记录后台处理请求 } commonServ.addHttpRequestLog( req_url, req.getMethod(), BlogUtil.getClientIP(req), agent, referer, Integer.valueOf(String.valueOf(System.currentTimeMillis()-start_time)), ///admin开头是访问后台页面 不能算入博客名 req_url.matches("^/admin/.*")?"51so":req_blog ); } catch (Exception e) { log.error("user:{}|agent:{}|referer:{}|ip:{}|method:{}",null==bu.getCurrentUser()?"guest":bu.getCurrentUser().getUserName(),req.getHeader("User-Agent"),referer,BlogUtil.getClientIP(req),req.getMethod()); log.error(URLDecoder.decode(req.getRequestURL().toString(), "UTF-8"), e); } } public void filter(HttpServletRequest req,HttpServletResponse rep,ServletRequest request, ServletResponse response, FilterChain chain,String url,BlogUtil bu,String referer) throws Exception{ //处理.do和druid的请求 if (url.endsWith(".do")||url.matches(".*\\.do;jsessionid=\\w{32}.*")||url.matches("\\/druid.*")) { //新浪微博登录 if (url.matches(".*(sinawblogin).do$")) { bu.setSinaLoginReferer(referer); rep.sendRedirect(sinaWeiBoLoginUrl); }else if (url.matches("^/pub/.*")) { chain.doFilter(request, response); }else{ UserVo u = bu.getCurrentUser(); if (null==u) { String rurl=String.format("%s://%s%s%s", (commonServ.isDebug()?"http":"https"),commonServ.getHost(),"/pub/login.do?url=",req.getRequestURL().toString()); rep.sendRedirect(rurl); return; }else if (url.matches("^/font/.*")) { chain.doFilter(request, response); }else if (!u.getUserLevel().equals("admin")) { log.error("拦截用户:{} 请求链接:{}",u.getUserName(),url); rep.sendError(403); }else if(null==u.getUserEmailActivate()||!u.getUserEmailActivate()){ req.setAttribute("msg", "系统升级,必须完成邮箱验证!"); req.getRequestDispatcher("/admin/profile.do").forward(request, response); return; } else{ req.getSession().setAttribute(Variable.FT_ADMIN_BLOG_PREFIX.getKey(),String.format("http://%s", commonServ.getHost())); chain.doFilter(request, response); } } }else{ blogname=getBlogName(url,req); if (null!=blogname&&blogname.equals("www")) { if (url.matches("\\/q")) { req.getRequestDispatcher("/q").forward(request, response); }else if(url.equals("/")){ req.getRequestDispatcher("/websitehome").forward(request, response); }else if (url.endsWith("sitemap.xml")) { rep.sendError(403); } else{ chain.doFilter(request, response); } return; } WebSite web = null; if (null!=blogname){ web = websiteServ.getWebSite(blogname); } if (null==web||null==blogname) { rep.sendError(404, String.format("博客 %s 不存在 not found ...", blogname)); }else{ skinVariable.setVariable(req, web,BLOG_MODEL.FONT_MODEL); //博客站点对象 req.getSession().setAttribute(Variable.SESSION_BLOG_WEBSITE.getKey(), web); if (url.matches("(\\/\\w+)?\\/entry/.*")) { //entry 文章跳转 统一用:/entry/\\w{32}.html 访问 但要兼容以前的 /用户名/entry/\\w{32}.html req.getRequestDispatcher(String.format("%s%s%s", "/entry","/",BlogUrlHelper.getLastSlashData(url))).forward(request, response); }else if (url.matches("(\\/\\w+)?\\/tags/.*")) { //tags 标签跳转 统一用:/tags/xxx 访问 但要兼容以前的 /用户名/tags/xxx if (!urlValidateServ.validateLable(web.getId(),url))rep.sendError(404); req.getRequestDispatcher(String.format("%s%s%s", "/tags","/",BlogUrlHelper.getLastSlashData(url))).forward(request, response); }else if (url.matches("(\\/\\w+)?\\/category/.*")) { //category 类型跳转 统一用:/category/xxx 访问 但要兼容以前的 /用户名/category/xxx if (!urlValidateServ.validateCategory(web.getId(),url))rep.sendError(404); req.getRequestDispatcher(String.format("%s%s%s", "/category","/",BlogUrlHelper.getLastSlashData(url))).forward(request, response); }else if (url.matches("(\\/\\w+)?\\/date/\\d{6,8}")) { //date 日期跳转 统一用:/date/xxx 访问 但要兼容以前的 /用户名/date/xxx if (!urlValidateServ.validateDate(web.getId(),url))rep.sendError(404); req.getRequestDispatcher(String.format("%s%s%s", "/date","/",BlogUrlHelper.getLastSlashData(url))).forward(request, response); }else if (url.endsWith("sitemap.xml")) { sitemap(req, rep, web.getId()); }else if (url.matches("(\\/\\w+)?\\/article_lis")) { //博文目录 req.getRequestDispatcher("/article_lis").forward(request, response); }else if (url.matches("(\\/\\w+)?\\/lable_lis")) { //热门标签 req.getRequestDispatcher("/lable_lis").forward(request, response); } else if (url.matches("(\\/\\w+)?\\/bookmark_lis")) { //书签 req.getRequestDispatcher("/bookmark_lis").forward(request, response); }else if (url.matches("(\\/\\w+)?\\/blog-msgboard")) { //留言板 req.getRequestDispatcher("/blog-msgboard").forward(request, response); }else if (url.matches("(\\/\\w+)?\\/blog-timeline")) { //时光轴 req.getRequestDispatcher("/blog-timeline").forward(request, response); }else if (url.matches("(\\/\\w+)?\\/article_timeline")) { //文章归档 req.getRequestDispatcher("/article_timeline").forward(request, response); } else{ boolean jump=true; if (Subdomain(req.getRequestURL().toString())) { //如果是子域名 if(url.equals("/")){ req.getRequestDispatcher("/home").forward(request, response); jump=false; } }else { if(url.matches("\\/\\w*(\\/)?")){ req.getRequestDispatcher("/home").forward(request, response); jump=false; }else if (url.matches("\\/\\w*\\/query")) { req.getRequestDispatcher("/query").forward(request, response); jump=false; } } if (jump) { chain.doFilter(request, response); } } } } } /** * 是否是子域名的方式 * @param url * @return */ public boolean Subdomain(String url){ return url.matches(String.format("http://\\w+.%s.*", commonServ.getHost())); } /** * 得到博客的名字 * @param url * @return */ public String getBlogName(String url,HttpServletRequest req){ String domain=req.getRequestURL().toString(); if (Subdomain(domain)) { String name=""; Pattern p = Pattern.compile(":\\//\\w+"); Matcher m = p.matcher(req.getRequestURL()); while(m.find()) { name=m.group().replaceAll("\\W+", ""); } if (name.equals("www")) { //兼容http://www.51so.info/博客名/entry/ if (url.matches("^\\/\\w+\\/(entry|tags|category|date)/.*")) { return url.split("/")[1]; } } return name; }else if (url.endsWith(".do")||url.matches(".*\\.do;jsessionid=\\w{32}$")) { User u = (User) req.getSession().getAttribute(BlogUtil.CURRENT_USER); return null==u?url.split("/")[1]:u.getUserName(); }else if (url.matches("/q")){ return defaultBolg; } /*else if (commonServ.isDebug()&&domain.matches("^http(s)?://localhost/.*")) { //开发模式下的url映射 String keywords[]=domain.replace("//", "").split("/"); return keywords[1]; }*/else{ String words[]=url.split("/"); return words.length==0?defaultBolg:words[1]; } } public void sitemap(HttpServletRequest req,HttpServletResponse rep,String websiteid) throws Exception{ long startDate=System.currentTimeMillis(); Map<String, Object> _data=new HashMap<String, Object>(); rep.setContentType("text/xml;charSet=UTF-8"); String templateName="/system/sitemap.html"; List<?> lis =articleServ.getSiteMapByWebSite(websiteid); _data.put("data", lis); _data.put("host", commonServ.getHost()); _data.put("millisecond", System.currentTimeMillis()-startDate); _data.put("blog_url_prefix", String.format("http://%s.%s", blogname,commonServ.getHost())); tsu.renderTemplate(req, rep, _data, templateName); } @Override public void init(FilterConfig filterConfig) throws ServletException { } public static void main(String[] args) { //www/skin/green/img/def-bg.jpg System.out.println("/kingschan/tags/中文12aA-_".matches("(\\/\\w+)?\\/tags/[\u4e00-\u9fa5|\\w|\\-]+")); } }