text: package qunar.tc.qconfig.server.web;
  
  import com.google.common.base.Splitter;
  import com.google.common.base.Strings;
  import com.google.common.collect.ImmutableSet;
  import com.google.common.io.CharSource;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import org.slf4j.MDC;
  import org.springframework.context.ApplicationContext;
  import org.springframework.web.context.support.WebApplicationContextUtils;
  import qunar.tc.qconfig.client.Configuration;
  import qunar.tc.qconfig.client.Feature;
  import qunar.tc.qconfig.client.MapConfig;
  import qunar.tc.qconfig.client.TypedConfig;
  import qunar.tc.qconfig.common.util.Constants;
  import qunar.tc.qconfig.common.util.ProfileUtil;
  import qunar.tc.qconfig.common.util.TokenUtil;
  import qunar.tc.qconfig.server.support.monitor.Monitor;
  import qunar.tc.qconfig.server.support.context.ClientInfoService;
  import qunar.tc.qconfig.servercommon.service.EnvironmentMappingService;
  
  import javax.servlet.*;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import java.io.IOException;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  /**
   * User: zhaohuiyu
   * Date: 5/14/14
   * Time: 2:27 PM
   */
  public class TokenFilter implements Filter {
      private static final Logger logger = LoggerFactory.getLogger(TokenFilter.class);
  
      private ClientInfoService clientInfoService;
  
      private EnvironmentMappingService envMappingService;
  
      private static volatile Set<String> forbiddenApps = ImmutableSet.of();
      private static volatile Set<String> whiteListApps = ImmutableSet.of();
  
      private static final String APP = "app";
  
      static {
          TypedConfig<String> typedConfig = TypedConfig.get("forbidden.app", Feature.create().setFailOnNotExists(false).build(), TypedConfig.STRING_PARSER);
          typedConfig.current();
          typedConfig.addListener(new Configuration.ConfigListener<String>() {
              @Override
              public void onLoad(String conf) {
                  try {
                      ImmutableSet.Builder<String> builder = new ImmutableSet.Builder<String>();
                      List<String> lines = CharSource.wrap(conf).readLines();
                      for (String line : lines) {
                          line = line.trim();
                          if (Strings.isNullOrEmpty(line)) {
                              continue;
                          }
                          builder.add(line);
                      }
                      forbiddenApps = builder.build();
                      logger.info("forbidden apps is [{}]", forbiddenApps);
                  } catch (IOException e) {
                      logger.error("unexpected error", e);
                  }
              }
          });
          MapConfig mapConfig = MapConfig.get("config.properties");
          mapConfig.asMap();
          mapConfig.addListener(new Configuration.ConfigListener<Map<String, String>>() {
              @Override
              public void onLoad(Map<String, String> conf) {
                  String whiteListAppStr = conf.get("whiteListApps");
                  if (!Strings.isNullOrEmpty(whiteListAppStr)) {
                      whiteListApps = new HashSet<>(Splitter.on(",").trimResults().omitEmptyStrings().splitToList(whiteListAppStr));
                  }
              }
          });
      }
  
      @Override
      public void init(FilterConfig filterConfig) throws ServletException {
          ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(filterConfig.getServletContext());
          if (context == null) {
              throw new ServletException("init failed");
          }
  
          envMappingService = context.getBean(EnvironmentMappingService.class);
          clientInfoService = context.getBean(ClientInfoService.class);
      }
  
      @Override
      public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
          HttpServletRequest request = (HttpServletRequest) servletRequest;
          HttpServletResponse response = (HttpServletResponse) servletResponse;
  
          String token = request.getHeader(Constants.TOKEN_NAME);
          String subEnv = request.getHeader(Constants.SUB_ENV);
          String env = request.getHeader(Constants.ENV_NAME);
  
          logger.debug("client access config, profile {}, token: {}", subEnv, token);
  
          String group = TokenUtil.decode(token);
  
          if (group == null) {
              logger.error("decode client token failed, token: {}", token);
              Monitor.forbidAccessCounter.inc();
              response.setStatus(HttpServletResponse.SC_FORBIDDEN);
              return;
          }
  
          if (forbiddenApps.contains(group)) {
              logger.debug("forbidden app access, [{}]", group);
              Monitor.forbidAppAccessCounter.inc();
              response.setStatus(HttpServletResponse.SC_FORBIDDEN);
              return;
          }
  
          clientInfoService.setGroup(group);
          clientInfoService.setEnv(env);
          String clientProfile = Strings.isNullOrEmpty(subEnv) ? env + ":" : env + ":" + subEnv;
          clientInfoService.setProfile(clientProfile);
          if (whiteListApps.contains(group)) {
              logger.debug("app:[{}] in white list", group);
              String reqGroup = request.getParameter(Constants.GROUP_NAME);
              String reqProfile = request.getParameter("reqProfile");
              if (!Strings.isNullOrEmpty(reqGroup) && ProfileUtil.legalProfile(reqProfile)) {
                  clientInfoService.setGroup(reqGroup);
                  clientInfoService.setProfile(reqProfile);
                  int idx = reqProfile.indexOf(":");
                  clientInfoService.setEnv(reqProfile.substring(0, idx));
              }
          }
  
          ((HttpServletResponse) servletResponse).setHeader("Connection", "keep-alive");
          servletResponse.setContentType(Constants.DEFAULT_CONTENT_TYPE);
          try {
              MDC.put(APP, group);
              filterChain.doFilter(servletRequest, servletResponse);
          } finally {
              MDC.remove(APP);
          }
      }
  
      @Override
      public void destroy() {
      }
  }
  