PermitedRequestConfiguration.java

  1. package cn.home1.oss.lib.security.starter;

  2. import static cn.home1.oss.boot.autoconfigure.AppType.RESOURCE;
  3. import static com.google.common.collect.Lists.newArrayList;
  4. import static com.google.common.collect.Sets.newLinkedHashSet;
  5. import static java.util.stream.Collectors.groupingBy;
  6. import static java.util.stream.Collectors.mapping;
  7. import static java.util.stream.Collectors.toList;
  8. import static org.apache.commons.lang3.StringUtils.isBlank;
  9. import static org.apache.commons.lang3.StringUtils.isNotBlank;

  10. import com.google.common.collect.ImmutableMap;

  11. import cn.home1.oss.boot.autoconfigure.AppProperties;
  12. import cn.home1.oss.boot.autoconfigure.AppSecurityProperties;
  13. import cn.home1.oss.lib.security.internal.VerifyCodeFilter;

  14. import org.springframework.beans.factory.annotation.Autowired;
  15. import org.springframework.boot.autoconfigure.h2.H2ConsoleProperties;
  16. import org.springframework.boot.autoconfigure.security.SecurityProperties;
  17. import org.springframework.boot.autoconfigure.security.SpringBootWebSecurityConfiguration;
  18. import org.springframework.context.annotation.Bean;
  19. import org.springframework.context.annotation.Configuration;
  20. import org.springframework.core.annotation.Order;
  21. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  22. import org.springframework.security.config.annotation.web.builders.WebSecurity;
  23. import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
  24. import org.springframework.security.web.util.matcher.AnyRequestMatcher;
  25. import org.springframework.security.web.util.matcher.OrRequestMatcher;
  26. import org.springframework.security.web.util.matcher.RequestMatcher;

  27. import java.util.Collection;
  28. import java.util.List;
  29. import java.util.Map;
  30. import java.util.Set;

  31. /**
  32.  * see: {@link SpringBootWebSecurityConfiguration} IgnoredPathsWebSecurityConfigurerAdapter.
  33.  *
  34.  * Created by zhanghaolun on 16/8/19.
  35.  */
  36. @Order(PermitedRequestConfiguration.ORDER_PERMITED_REQUEST)
  37. @Configuration
  38. public class PermitedRequestConfiguration extends SecurityConfigurerAdapter<PermitedRequestConfiguration> {

  39.   public static final String PERMITED_REQUESTS = "permitedRequests";
  40.   public static final String PERMITED_REQUEST_MATCHER = "permitedRequestMatcher";

  41.   public static final int ORDER_PERMITED_REQUEST = SecurityProperties.IGNORED_ORDER + 1;

  42.   @Autowired
  43.   private AppProperties appProperties;

  44.   @Autowired(required = false)
  45.   private VerifyCodeFilter verifyCodeFilter;

  46.   @Autowired(required = false)
  47.   private H2ConsoleProperties h2ConsoleProperties;

  48.   @Override
  49.   public void init(final WebSecurity web) {
  50.     final Set<String> ignored = newLinkedHashSet();
  51.     // ! TODO ! 其它地方似乎也加了这些, 条件开启, 重复代码 see: Swagger2DocumentationAutoConfiguration.swaggerRequestMatcher
  52.     // default is: /v2/api-docs
  53.     //ignored.add("/webjars/**");
  54.     //ignored.add(this.environment.getProperty("springfox.documentation.swagger.v1.path", "/v1/**"));
  55.     //ignored.add(this.environment.getProperty("springfox.documentation.swagger.v2.path", "/v2/**"));
  56.     //ignored.addAll(newArrayList("/swagger-ui.html", "/swagger-resources/**"));

  57.     ignored.add("/h2-console/**");
  58.     if (this.h2ConsoleProperties != null) {
  59.       final String path = this.h2ConsoleProperties.getPath();
  60.       final String antPattern = (path.endsWith("/") ? path + "**" : path + "/**");
  61.       ignored.add(antPattern);
  62.     }

  63.     // create another filterChain after spring-boot's default (security.ignored) filterChain
  64.     if (!ignored.isEmpty()) {
  65.       final List<RequestMatcher> matchers = ignored.stream() //
  66.         .map(pattern -> new AntPathRequestMatcher(pattern, null)) //
  67.         .collect(toList());
  68.       final RequestMatcher requestMatcher = new OrRequestMatcher(matchers);
  69.       web.ignoring().requestMatchers(requestMatcher);
  70.     }
  71.   }

  72.   @Override
  73.   public void configure(final HttpSecurity http) {
  74.     // empty-impl
  75.   }

  76.   @Bean(name = PERMITED_REQUEST_MATCHER)
  77.   public RequestMatcher permitedRequestMatcher() {
  78.     final RequestMatcher result;
  79.     if (this.appProperties.getSecurityEnabled()) {
  80.       // requestMatchers must contain a value
  81.       final List<RequestMatcher> antMatchers = this.permitedRequests().entrySet().stream()
  82.         .flatMap(entry -> entry.getValue().stream().map(pattern -> //
  83.           isBlank(entry.getKey()) //
  84.             ? new AntPathRequestMatcher(pattern) : new AntPathRequestMatcher(pattern, entry.getKey())
  85.         )).collect(toList());
  86.       result = antMatchers.isEmpty() ? request -> false : new OrRequestMatcher(antMatchers);
  87.     } else {
  88.       result = AnyRequestMatcher.INSTANCE;
  89.     }
  90.     return result;
  91.   }

  92.   @Bean(name = PERMITED_REQUESTS)
  93.   public Map<String, List<String>> permitedRequests() {
  94.     // permit的还是要过filter和authenticationManager
  95.     final AppSecurityProperties security = this.appProperties.getSecurity();

  96.     final String loginPage = security.getLoginPage();

  97.     final Collection<String> defaultPermited = this.appProperties.getType() != RESOURCE ? //
  98.       newLinkedHashSet(newArrayList( //
  99.         security.getLoginPublicKeyUrl(), loginPage, security.getLoginProcessingUrl(), //
  100.         security.getLogoutUrl() + "/*", security.getLogoutUrl() //
  101.       )) : newArrayList();

  102.     final Collection<String> permitedRequests = newLinkedHashSet();

  103.     if (isNotBlank(security.getPermited())) {
  104.       permitedRequests.addAll(newArrayList(security.getPermited().split("[ ]*,[ ]*")));
  105.     }

  106.     permitedRequests.addAll(defaultPermited);

  107.     if (this.verifyCodeFilter != null) {
  108.       permitedRequests.add(this.verifyCodeFilter.getCodeUrl());
  109.     }

  110.     final Map<String, List<String>> grouped = permitedRequests.stream()
  111.       .map(expression -> {
  112.         final String[] fragments = expression.split(":");
  113.         return fragments.length == 1 //
  114.           ? newArrayList("", fragments[0]) : newArrayList(fragments[0].toUpperCase(), fragments[1]);
  115.       })
  116.       .collect(groupingBy(o -> o.get(0), mapping(o -> o.get(1), toList())));

  117.     return ImmutableMap.copyOf(grouped);
  118.   }
  119. }