Java 对每个API调用进行身份验证

Java 对每个API调用进行身份验证,java,spring-boot,Java,Spring Boot,我目前有一个通过登录页面进行身份验证的Spring服务。现在需要的是有一种使用客户机证书和私钥对每个API请求的用户进行身份验证的方法。我创建了一个到外部端点的POST请求,我正在使用该请求对用户进行身份验证。我能够在身份验证过滤器中对用户进行身份验证,但随后它显示405错误 public class AuthenticationFilter extends GenericFilterBean { private AuthenticationManager authentication

我目前有一个通过登录页面进行身份验证的Spring服务。现在需要的是有一种使用客户机证书和私钥对每个API请求的用户进行身份验证的方法。我创建了一个到外部端点的POST请求,我正在使用该请求对用户进行身份验证。我能够在身份验证过滤器中对用户进行身份验证,但随后它显示405错误

public class AuthenticationFilter extends GenericFilterBean {

    private AuthenticationManager authenticationManager;

    public AuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest http_request = (HttpServletRequest) request;
        HttpServletResponse http_response = (HttpServletResponse) response;

        String cert_filename = "certificate.pem";
        File cert_file = new File(cert_filename);

        if(cert_file.createNewFile())
            System.out.println("Successfully created private cert file");
        else
            System.out.println("Cert file could not be created");

        BufferedWriter cert_writer = new BufferedWriter(new FileWriter(cert_filename));
        cert_writer.write(cert);
        cert_writer.close();

        String key_filename = "private_key.key";
        File key_file = new File(key_filename);

        if(key_file.createNewFile())
            System.out.println("Successfully created private key file");
        else
            System.out.println("Key file could not be created");

        BufferedWriter key_writer = new BufferedWriter(new FileWriter(key_filename));
        key_writer.write(key);
        key_writer.close();

        ProcessBuilder processBuilder = new ProcessBuilder();
        processBuilder.redirectErrorStream(true);
        processBuilder.command("curl", ..., ...);
        Process process = processBuilder.start();
        BufferedReader reader =
                new BufferedReader(new InputStreamReader(process.getInputStream()));
        StringBuilder builder = new StringBuilder();
        String line;
        while ( (line = reader.readLine()) != null) {
            builder.append(line);
            builder.append(System.getProperty("line.separator"));
        }
        String result = builder.toString();

        System.out.println(result);
        if(result.contains("\"successful\": true")) {
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("user", "password");
            Authentication auth = authenticationManager.authenticate(token);
            SecurityContextHolder.getContext().setAuthentication(auth);
//            TokenResponse tokenResponse = new TokenResponse(auth.getDetails().toString());
//            String tokenJsonResponse = new ObjectMapper().writeValueAsString(tokenResponse);
            http_response.setStatus(HttpServletResponse.SC_OK);
            //http_response.sendError(HttpServletResponse.SC_OK);
//            http_response.addHeader("Content-Type", "application/json");
//            http_response.getWriter().print(tokenJsonResponse);
            chain.doFilter(request, response);
        }
        else{
            http_response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            http_response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
        }

    }
}


@EnableWebSecurity
@Order(1000)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    RestAuthenticationEntryPoint restAuthenticationEntryPoint;

    String[] permitted  =  {
            "/login",
            ...
    };

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("user")
                .password("{noop}password")
                .roles("USER");

    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint)
                .and()
                .authorizeRequests()
                .antMatchers(permitted).permitAll()
                .anyRequest().authenticated()
                .and()
                .oauth2Login()
                .loginPage("/login")
                .defaultSuccessUrl("/swagger-ui.html", true)
                .and()
                .logout()
                .clearAuthentication(true)
                .logoutUrl("/logout")
                .logoutSuccessUrl("/login").permitAll()
                .deleteCookies("JSESSIONID")
                .invalidateHttpSession(true);
        http.addFilterAfter(new AuthenticationFilter(authenticationManager()), BasicAuthenticationFilter.class);
    }


}
现在需要的是使用客户机证书和私钥对每个API请求的用户进行身份验证

显然,您缺少了一些非常基本的原则,即ssl上的客户端身份验证是如何工作的。其思想是,客户端拥有其密钥对私钥和公钥以及需要由可信证书颁发机构签名的证书

出于测试目的,您可以使用自签名证书,只需在信任库中信任它,请参阅下面的博客链接

身份验证将在通道https级别和客户端信息证书dn,。。由引擎作为标头或请求上下文传递

您可以浏览以下博客:


我通常会将外部资源中的相关信息复制到答案中,但在这种情况下,我会复制整个帖子。

你必须使用curl吗?可以从代码中进行简单调用吗?为什么您可以访问私钥?我不必使用curl,但我希望能够接收证书作为用户的输入。我还没有找到一种不使用Java密钥库通过简单调用来实现这一点的方法。私钥需要与证书一起传递到外部终结点。出现问题。私钥永远不应该被传递出去。如果您出于任何目的提供它,它就不再是私有的。如果将私钥保存到环境变量中,这仍然是一个问题吗?身份验证终结点只能以这种方式访问,我无法控制它,因为它是我正在进行身份验证的外部服务。我还想补充一点,服务器必须通过将客户端身份验证设置为可选或所需来请求客户端的证书。对于不同类型的容器apache httpd、tomcat、nginx等有不同的设置。。。。您需要查找容器/代理设置的特定语法。实际上,设置X509身份验证取决于所使用的容器和SSL终止点。因此,将curl的-key参数与私钥一起使用是否是命中端点的错误做法?@其他人这不仅仅是错误做法,根本不起作用。您可以尝试搜索/阅读有关双方ssl的更多信息