All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.home1.oss.lib.security.swagger.SecurityApiDocumentationPlugin Maven / Gradle / Ivy

There is a newer version: 1.0.8.OSS
Show newest version
package cn.home1.oss.lib.security.swagger;

import static cn.home1.oss.boot.autoconfigure.AppType.RESOURCE;
import static com.google.common.base.Predicates.or;
import static com.google.common.collect.Lists.newArrayList;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import static org.springframework.http.MediaType.TEXT_HTML_VALUE;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import static springfox.documentation.builders.PathSelectors.regex;

import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.Sets;

import cn.home1.oss.boot.autoconfigure.AppProperties;
import cn.home1.oss.boot.autoconfigure.AppSecurityProperties;
import cn.home1.oss.lib.common.crypto.KeyExpression;
import cn.home1.oss.lib.errorhandle.api.ResolvedError;
import cn.home1.oss.lib.security.api.GenericUser;
import cn.home1.oss.lib.security.internal.rest.RestfulLoginPublicKeyFilter;
import cn.home1.oss.lib.swagger.ManualRequestHandler;
import cn.home1.oss.lib.swagger.SwaggerUtils;
import cn.home1.oss.lib.swagger.model.ApiOperationInfo;
import cn.home1.oss.lib.swagger.model.ApiRequest;

import com.fasterxml.classmate.TypeResolver;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.condition.ConsumesRequestCondition;
import org.springframework.web.servlet.mvc.condition.HeadersRequestCondition;
import org.springframework.web.servlet.mvc.condition.ParamsRequestCondition;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.ProducesRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;

import springfox.documentation.RequestHandler;
import springfox.documentation.builders.ResponseMessageBuilder;
import springfox.documentation.schema.DefaultGenericTypeNamingStrategy;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ResponseMessage;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.DocumentationPlugin;
import springfox.documentation.spi.service.contexts.DocumentationContext;
import springfox.documentation.spi.service.contexts.DocumentationContextBuilder;
import springfox.documentation.swagger.common.SwaggerPluginSupport;

import java.util.EnumMap;
import java.util.List;
import java.util.Map;

/**
 * equivalent to @Bean public Docket securityDocket() {... }.
 */
@Order(value = SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER)
public class SecurityApiDocumentationPlugin implements DocumentationPlugin {

  @Autowired
  private TypeResolver typeResolver;
  @Autowired
  private AppProperties appProperties;

  @Override
  public DocumentationContext configure(final DocumentationContextBuilder documentationContextBuilder) {
    documentationContextBuilder
      .apiInfo(SwaggerUtils.apiInfo("oss-lib-security", "oss-lib-security's security endpoints"))
      .groupName("security")
      .pathMapping(Optional.absent())
      .genericsNaming(new DefaultGenericTypeNamingStrategy())
      .requestHandlers(this.requestHandlers())
      .additionalModels(Sets.newHashSet(this.typeResolver.resolve(ResolvedError.class)));
    return documentationContextBuilder.build();
  }

  private List requestHandlers() {
    final AppSecurityProperties appSecurityProperties = this.appProperties.getSecurity();
    // TODO add oauth endpoints
    // TODO conditional filter
    // finish how to add description
    final List result = newArrayList();
    if (appSecurityProperties.getEnabled() && this.appProperties.getType() != RESOURCE) {
      result.add( // formAuth loginPage
        ManualRequestHandler.requestHandlerBuilder()
          .consumes(new ConsumesRequestCondition())
          .declaringClass(DefaultLoginPageGeneratingFilter.class)
          .groupName(DefaultLoginPageGeneratingFilter.class.getSimpleName())
          .headers(new HeadersRequestCondition())
          .parameters(newArrayList())
          .params(new ParamsRequestCondition())
          .patternsCondition(new PatternsRequestCondition(appSecurityProperties.getLoginPage()))
          .produces(new ProducesRequestCondition(TEXT_HTML_VALUE))
          .returnType(this.typeResolver.resolve(String.class))
          .supportedMethods(new RequestMethodsRequestCondition(GET))
          .build()
      );
      result.add( // formAuth loginProcessingUrl
        ManualRequestHandler.requestHandlerBuilder()
          .consumes(new ConsumesRequestCondition())
          .declaringClass(UsernamePasswordAuthenticationFilter.class)
          .groupName(UsernamePasswordAuthenticationFilter.class.getSimpleName())
          .headers(new HeadersRequestCondition())
          .parameters(newArrayList( //
            //  new ResolvedMethodParameter("username", null, TYPE_RESOLVER.resolve(String.class))
          ))
          .apiOperationInfo(ApiOperationInfo.builder()
            .notes("用户登录请求处理")
            .apiRequest(ApiRequest.builder()
              .parameters(newArrayList())
              .build()
              .addParameter("username", "enter your user name", true)
              .addParameter("password", "enter your password", true)
              .addParameter("_csrf", "Cross-site request forgery", false)
              .addParameter("remember-me", "So remember me?", false))
            .build()
          ).patternsCondition(new PatternsRequestCondition(appSecurityProperties.getLoginProcessingUrl()))
          .produces(new ProducesRequestCondition(APPLICATION_JSON_VALUE))
          .returnType(this.typeResolver.resolve(GenericUser.class))
          .supportedMethods(new RequestMethodsRequestCondition(POST))
          .build()

      );
      result.add( // formAuth loginPublicKeyUrl
        ManualRequestHandler.requestHandlerBuilder()
          .consumes(new ConsumesRequestCondition())
          .declaringClass(RestfulLoginPublicKeyFilter.class)
          .groupName(RestfulLoginPublicKeyFilter.class.getSimpleName())
          .headers(new HeadersRequestCondition())
          .parameters(newArrayList())
          .params(new ParamsRequestCondition())
          .patternsCondition(new PatternsRequestCondition(appSecurityProperties.getLoginPublicKeyUrl()))
          .produces(new ProducesRequestCondition(APPLICATION_JSON_VALUE))
          .returnType(this.typeResolver.resolve(KeyExpression.class))
          .supportedMethods(new RequestMethodsRequestCondition(GET))
          .build()
      );
      result.add( // formAuth logoutUrl
        ManualRequestHandler.requestHandlerBuilder()
          .consumes(new ConsumesRequestCondition())
          .declaringClass(LogoutFilter.class)
          .groupName(LogoutFilter.class.getSimpleName())
          .headers(new HeadersRequestCondition())
          .parameters(newArrayList())
          .params(new ParamsRequestCondition())
          .patternsCondition(new PatternsRequestCondition(appSecurityProperties.getLogoutUrl()))
          .produces(new ProducesRequestCondition(APPLICATION_JSON_VALUE))
          .returnType(this.typeResolver.resolve(Void.class))
          .supportedMethods(new RequestMethodsRequestCondition(POST))
          .build()
      );
    }
    return result;
  }

  @Override
  public DocumentationType getDocumentationType() {
    return DocumentationType.SWAGGER_2;
  }

  @Override
  public String getGroupName() {
    return "security";
  }

  @Override
  public boolean isEnabled() {
    return true;
  }

  @Override
  public boolean supports(final DocumentationType delimiter) {
    return DocumentationType.SWAGGER_2.equals(delimiter);
  }

  /**
   * @return securityPaths
   * @deprecated remove this later.
   */
  @Deprecated
  public Predicate securityPaths() {
    final String securityBasePath = this.appProperties.getSecurity().getBasePath();
    return or(regex(securityBasePath + "/.*"), regex("/oauth/.*"));
  }

  private static List responseMessages() {
    final List responseMessages = newArrayList();
    responseMessages.add(new ResponseMessageBuilder()
      .code(400).message("400diy")
      .responseModel(new ModelRef("cn.home1.oss.lib.errorhandle.api.ResolvedError"))
      .build());
    return responseMessages;
  }

  /**
   * @return responseMessages
   * @deprecated remove this later.
   */
  @Deprecated
  static Map> additionalResponseMessages() {
    final Map> additionalResponseMessages = new EnumMap<>(RequestMethod.class);
    final List responseMessages = responseMessages();
    for (final RequestMethod requestMethod : RequestMethod.values()) {
      additionalResponseMessages.put(requestMethod, responseMessages);
    }
    return additionalResponseMessages;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy