java - Spring boot+Spring Security 单向 SSL 和双向 SSL 应用端点

标签 java spring ssl spring-security spring-boot

我有一个包含 5 个 REST API 的 Web 应用程序。所有 API 都是启用了 SSL 的 HTTPS。 这是 server.xml 中的连接器标记:

 <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
                maxThreads="150" scheme="https" secure="true"
                keystoreFile="conf/jks/ketStore.jks" keystorePass="keystore" keystoreType="jks"
                truststoreFile="conf/jks/trustStore.jks" truststorePass="truststore" truststoreType="jks"
                clientAuth="true" sslProtocol="TLSv1.2"/>

现在我只需要使用单向 SSL 通过 HTTP 公开其中一个 API。其他 4 个 API 应该只能通过 HTTPS 和双向 SSL 证书访问。

使用 Spring boot 和 Spring 4 Security 解决这个问题的最佳方法是什么。

更新

我在这方面取得了一些进展。我已经设置了 clientAuth="want" 并且无需在客户端出示证书就可以访问所需的 API。但我不确定如何为其他 API 强制执行 2-way 并编写自定义过滤器来检查 SSL 握手。有没有办法在 Spring Security 中做到这一点。

我有以下 MultiHttpSecurityConfig 类:

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MultiHttpSecurityConfig {

  private static final Logger LOG = LoggerFactory
      .getLogger(MultiHttpSecurityConfig.class);


  @Configuration
  @Order(1)
  public static class SecureApiConfigurationAdapter extends
      WebSecurityConfigurerAdapter {

    @Autowired
    private HttpAuthEntryPoint httpAuthEntryPoint;

    @Autowired
    private X509UserDetSer x509UserUserDetSer;

    protected void configure(
        final HttpSecurity http)
        throws Exception {
      LOG.debug("/SSL2waysecureAPI/");
      http.csrf().disable()
          .antMatcher("/SSL2waysecureAPI/**")

          .x509()
          .subjectPrincipalRegex("CN=(.*?),")
          // .subjectPrincipalRegex(".*")
          .authenticationUserDetailsService(x509UserUserDetSer)
          .and().exceptionHandling()
          .authenticationEntryPoint(httpAuthEntryPoint)
          .and().sessionManagement()
          .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
  }

Tomcat 中新的连接器标签如下:

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
                maxThreads="150" scheme="https" secure="true"
                keystoreFile="conf/jks/ketStore.jks" keystorePass="keystore" keystoreType="jks"
                truststoreFile="conf/jks/trustStore.jks" truststorePass="truststore" truststoreType="jks"
                clientAuth="want" sslProtocol="TLSv1.2"/>

最佳答案

所以如果有人需要它 - 我以这种方式做了类似的事情

首先 - server.xml 配置文件

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
            maxThreads="150" scheme="https" secure="true"
            keystoreFile="conf/jks/ketStore.jks" keystorePass="keystore" keystoreType="jks"
            truststoreFile="conf/jks/trustStore.jks" truststorePass="truststore" truststoreType="jks"
            clientAuth="want" sslProtocol="TLSv1.2"/>

然后是 web.xml :

<filter>
    <filter-name>ServletFilter</filter-name>
    <filter-class>securechat.filter.ServletFilter</filter-class>
    <async-supported>true</async-supported>
</filter>

<filter-mapping>
    <filter-name>ServletFilter</filter-name>
    <url-pattern>/*</url-pattern>
 </filter-mapping>

之后,对任何端点的任何请求都将挂接到此过滤器。在其中,您可以手动检查任何请求。类似

@Component
public class ServletFilter implements Filter {

 public static final String X_CLACKS_OVERHEAD = "X-Clacks-Overhead";

    @Override
    public void doFilter(ServletRequest req, ServletResponse res,
                     FilterChain chain) throws IOException, ServletException {

    X509Certificate[] certificates = (X509Certificate[]) req
            .getAttribute("javax.servlet.request.X509Certificate");

    String servletPath = null;
    int port = -1;
    if (req instanceof HttpServletRequest) {
        servletPath = ((HttpServletRequest)req).getServletPath();
        port =  ((HttpServletRequest)req).getServerPort();

        System.out.println("getServletPath = " +  ((HttpServletRequest)req).getServletPath() );
        System.out.println(" ((HttpServletRequest)req).getServerPort() = " +   ((HttpServletRequest)req).getServerPort());

    //Just in memory of....
    HttpServletResponse response = (HttpServletResponse) res;
    response.setHeader(X_CLACKS_OVERHEAD, "GNU Terry Pratchett");


    //Here you can do checking for port and destination.
    if(port == 8080 && !servletPath.equals("/notSecureDest/something")
         //log error - we try to enter secured enpoint bu non-secured port and url
         return; // we decline request
    }else if(port == ??? && ???? ) {
        //if all checkings age good - we do
        chain.doFilter(req, res);
    }

} 

希望对您有所帮助。

关于java - Spring boot+Spring Security 单向 SSL 和双向 SSL 应用端点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37105027/

相关文章:

java - 配置问题: Unable to locate Spring NamespaceHandler for XML schema namespace [http://java. sun.com/xml/ns/javaee]

java - 从 Spring Aspect 调用不同的代理方法

java - Raspberry Pi 上的 HTTPS 太慢了。我该怎么办?我应该选择哪种密码?

java - 模拟 HttpHeaders 抛出 NullPointerException

java - 使用 Spring 3+Hibernate JPA 时发现 JPA 注释类

ssl - 使用 HTTP/HTTPS 混合代理目标站点的 PingAccess 问题

PHP curl 错误 :error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure

java - 如何获取动态创建的表格的表格宽度?

java - 在java中将Json数组转换为Map

java - 为什么变量应该声明为 static 和 Final