X.509 Authentication in Spring Security – Spring Security中的X.509认证

最后修改: 2016年 8月 25日


1. Overview


In this article, we’ll focus on the main use cases for X.509 certificate authentication – verifying the identity of a communication peer when using the HTTPS (HTTP over SSL) protocol.

在本文中,我们将重点讨论X.509证书认证的主要用例–在使用HTTPS(HTTP over SSL)协议时验证通信对等体的身份

Simply put – while a secure connection is established, the client verifies the server according to its certificate (issued by a trusted certificate authority).


But beyond that, X.509 in Spring Security can be used to verify the identity of a client by the server while connecting. This is called “mutual authentication”, and we’ll look at how that’s done here as well.

但除此之外,Spring Security中的X.509可用于在连接时由服务器验证客户的身份。这被称为“相互认证”,,我们也将在这里看看如何做到这一点。

Finally, we’ll touch on when it makes sense to use this kind of authentication.


To demonstrate server verification, we’ll create a simple web application and install a custom certificate authority in a browser.


Moreover, for mutual authentication, we’ll create a client certificate and modify our server to allow only verified clients.


It’s highly recommended to follow the tutorial step by step and create the certificates, as well as the keystore and the truststore, yourself, according to the instructions presented in the following sections. However, all the ready to use files can be found in our GitHub repository.

强烈建议按照教程的步骤,根据以下章节的说明,自己创建证书以及钥匙库和信任库。然而,在我们的GitHub 仓库中可以找到所有可使用的文件。

2. Self Signed Root CA


To be able to sign our server-side and client-side certificates, we need to create our own self-signed root CA certificate first. This way we’ll act as our own certificate authority.


For this purpose we’ll use openssl library, so we need to have it installed prior to following the next step.


Let’s now create the CA certificate:


openssl req -x509 -sha256 -days 3650 -newkey rsa:4096 -keyout rootCA.key -out rootCA.crt

When we execute the above command, we need to provide the password for our private key. For the purpose of this tutorial, we use changeit as a passphrase.


Additionally, we need to enter information that forms a so-called distinguished name. Here, we only provide the CN (Common Name) – Baeldung.com – and leave other parts empty.



3. Keystore


Optional Requirement: To use cryptographically strong keys together with encryption and decryption features we’ll need the “Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files” installed in our JVM.

可选的要求:为了在加密和解密功能中使用加密的强密钥,我们需要在我们的JVM中安装”Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files

These can be downloaded for example from Oracle (follow the installation instructions included in the download). Some Linux distributions also provide an installable package through their package managers.


A keystore is a repository that our Spring Boot application will use to hold our server’s private key and certificate. In other words, our application will use the keystore to serve the certificate to the clients during the SSL handshake.

密钥库是一个存储库,我们的Spring Boot应用程序将用它来保存我们服务器的私钥和证书。换句话说,我们的应用程序将使用钥匙库在SSL握手期间向客户提供证书。

In this tutorial, we use the Java Key-Store (JKS) format and a keytool command-line tool.


3.1. Server-side Certificate


To implement the server-side X.509 authentication in our Spring Boot application, we first need to create a server-side certificate.

为了在我们的Spring Boot应用程序中实现服务器端X.509认证,我们首先需要创建一个服务器端的证书。

Let’s start with creating a so-called certificate signing request (CSR):


openssl req -new -newkey rsa:4096 -keyout localhost.key –out localhost.csr

Similarly, as for the CA certificate, we have to provide the password for the private key. Additionally, let’s use localhost as a common name (CN).


Before we proceed, we need to create a configuration file – localhost.ext. It’ll store some additional parameters needed during signing the certificate.

在我们继续之前,我们需要创建一个配置文件 – localhost.ext。它将存储签署证书时需要的一些额外参数。

subjectAltName = @alt_names
DNS.1 = localhost

A ready to use file is also available here.


Now, it’s time to sign the request with our rootCA.crt certificate and its private key:


openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in localhost.csr -out localhost.crt -days 365 -CAcreateserial -extfile localhost.ext

Note that we have to provide the same password we used when we created our CA certificate.


At this stage, we finally have a ready to use localhost.crt certificate signed by our own certificate authority.


To print our certificate’s details in a human-readable form we can use the following command:


openssl x509 -in localhost.crt -text

3.2. Import to the Keystore


In this section, we’ll see how to import the signed certificate and the corresponding private key to the keystore.jks file.


We’ll use the PKCS 12 archive, to package our server’s private key together with the signed certificate. Then we’ll import it to the newly created keystore.jks.

我们将使用PKCS 12档案,将我们的服务器的私钥与签名的证书一起打包。然后我们将它导入到新创建的keystore.jks.中。

We can use the following command to create a .p12 file:


openssl pkcs12 -export -out localhost.p12 -name "localhost" -inkey localhost.key -in localhost.crt

So we now have the localhost.key and the localhost.crt bundled in the single localhost.p12 file.


Let’s now use keytool to create a keystore.jks repository and import the localhost.p12 file with a single command:


keytool -importkeystore -srckeystore localhost.p12 -srcstoretype PKCS12 -destkeystore keystore.jks -deststoretype JKS

At this stage, we have everything in place for the server authentication part. Let’s proceed with our Spring Boot application configuration.

在这个阶段,我们已经为服务器认证部分做好了一切准备。让我们继续进行我们的Spring Boot应用配置。

4. Example Application


Our SSL secured server project consists of a @SpringBootApplication annotated application class (which is a kind of @Configuration), an application.properties configuration file and a very simple MVC-style front-end.


All, the application has to do, is to present an HTML page with a “Hello {User}!” message. This way we can inspect the server certificate in a browser to make sure, that the connection is verified and secured.

应用程序所要做的,就是呈现一个带有“Hello {User}!”消息的HTML页面。这样,我们就可以在浏览器中检查服务器证书,以确保连接是经过验证和安全的。

4.1. Maven Dependencies


First, we create a new Maven project with three Spring Boot Starter bundles included:

首先,我们创建一个新的Maven项目,其中包含三个Spring Boot Starter捆绑包。


For reference: we can find the bundles on Maven Central (security, web, thymeleaf).

供参考:我们可以在Maven中心找到这些软件包(security, web, thymeleaf)。

4.2. Spring Boot Application

4.2.Spring Boot应用程序

As the next step, we create the main application class and the user-controller:


public class X509AuthenticationServer {
    public static void main(String[] args) {
        SpringApplication.run(X509AuthenticationServer.class, args);

public class UserController {
    @RequestMapping(value = "/user")
    public String user(Model model, Principal principal) {
        UserDetails currentUser 
          = (UserDetails) ((Authentication) principal).getPrincipal();
        model.addAttribute("username", currentUser.getUsername());
        return "user";

Now, we tell the application where to find our keystore.jks and how to access it. We set SSL to an “enabled” status and change the standard listening port to indicate a secured connection.

现在,我们告诉应用程序在哪里可以找到我们的keystore.jks以及如何访问它。我们将SSL设置为 “启用 “状态,并将标准监听端口改为表示安全连接。

Additionally, we configure some user-details for accessing our server via Basic Authentication:



This will be the HTML template, located at the resources/templates folder:


<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
    <title>X.509 Authentication Demo</title>
    <h2>Hello <span th:text="${username}"/>!</h2>

4.3. Root CA Installation


Before we finish this section and look at the site, we need to install our generated root certificate authority as a trusted certificate in a browser.


An exemplary installation of our certificate authority for Mozilla Firefox would look like follows:

Mozilla Firefox安装我们的证书颁发机构的一个范例看起来如下。

  1. Type about:preferences in the address bar
  2. Open Advanced -> Certificates -> View Certificates -> Authorities
  3. Click on Import
  4. Locate the Baeldung tutorials folder and its subfolder spring-security-x509/keystore
  5. Select the rootCA.crt file and click OK
  6. Choose “Trust this CA to identify websites” and click OK

Note: If you don’t want to add our certificate authority to the list of trusted authorities, you’ll later have the option to make an exception and show the website tough, even when it is mentioned as insecure. But then you’ll see a ‘yellow exclamation mark’ symbol in the address bar, indicating the insecure connection!


Afterward, we will navigate to the spring-security-x509-basic-auth module and run:


mvn spring-boot:run

Finally, we hit https://localhost:8443/user, enter our user credentials from the application.properties and should see a “Hello Admin!” message. Now we’re able to inspect the connection status by clicking the “green lock” symbol in the address bar, and it should be a secured connection.

最后,我们点击https://localhost:8443/user,从application.properties中输入我们的用户凭证,应该看到“Hello Admin!”消息。现在我们能够通过点击地址栏中的 “绿色锁 “符号来检查连接状态,它应该是一个安全连接。



5. Mutual Authentication


In the previous section, we presented how to implement the most common SSL authentication schema – server-side authentication. This means, only a server authenticated itself to clients.


In this section, we’ll describe how to add the other part of the authentication – client-side authentication. This way, only clients with valid certificates signed by the authority that our server trusts, can access our secured website.

在本节中,我们将描述如何添加认证的另一部分 – 客户端认证。这样,只有持有由我们服务器信任的权威机构签署的有效证书的客户才能访问我们的安全网站。

But before we continue, let’s see what are the pros and cons of using the mutual SSL authentication.




  • The private key of an X.509 client certificate is stronger than any user-defined password. But it has to be kept secret!
  • With a certificate, the identity of a client is well-known and easy to verify.
  • No more forgotten passwords!



  • We need to create a certificate for each new client.
  • The client’s certificate has to be installed in a client application. In fact: X.509 client authentication is device-dependent, which makes it impossible to use this kind of authentication in public areas, for example in an internet-café.
  • There must be a mechanism to revoke compromised client certificates.
  • We must maintain the clients’ certificates. This can easily become costly.

5.1. Truststore

5.1 信托商店

A trustsore in some way is the opposite of a keystore. It holds the certificates of the external entities that we trust.


In our case, it’s enough to keep the root CA certificate in the truststore.

在我们的案例中,将根 CA 证书保留在信任库中就足够了。

Let’s see how to create a truststore.jks file and import the rootCA.crt using keytool:


keytool -import -trustcacerts -noprompt -alias ca -ext san=dns:localhost,ip: -file rootCA.crt -keystore truststore.jks

Note, we need to provide the password for the newly created trusstore.jks. Here, we again used the changeit passphrase.


That’s it, we’ve imported our own CA certificate, and the truststore is ready to be used.


5.2. Spring Security Configuration


To continue, we are modifying our X509AuthenticationServer to configure HttpSecurity by creating a SecurityFilterChain Bean. Here we configure the x.509 mechanism to parse the Common Name (CN) field of a certificate for extracting usernames.


With this extracted usernames, Spring Security is looking up in a provided UserDetailsService for matching users. So we also implement this service interface containing one demo user.

有了这些提取的用户名,Spring Security在提供的UserDetailsService中查找匹配的用户。所以我们也实现了这个包含一个演示用户的服务接口。

Tip: In production environments, this UserDetailsService can load its users for example from a JDBC Datasource.

提示:在生产环境中,这个UserDetailsService可以从JDBC Datasource加载其用户。

You have to notice that we annotate our class with @EnableWebSecurity and @EnableGlobalMethodSecurity with enabled pre-/post-authorization.


With the latter we can annotate our resources with @PreAuthorize and @PostAuthorize for fine-grained access control:


@EnableGlobalMethodSecurity(prePostEnabled = true)
public class X509AuthenticationServer {

    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http.build();

    public UserDetailsService userDetailsService() {
        return new UserDetailsService() {
            public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
                if (username.equals("Bob")) {
                    return new User(username, "", 
                throw new UsernameNotFoundException("User not found!");

As said previously, we are now able to use Expression-Based Access Control in our controller. More specifically, our authorization annotations are respected because of the @EnableGlobalMethodSecurity annotation in our @Configuration:


public class UserController {
    @RequestMapping(value = "/user")
    public String user(Model model, Principal principal) {

An overview of all possible authorization options can be found in the official documentation.


As a final modification step, we have to tell the application where our truststore is located and that SSL client authentication is necessary (server.ssl.client-auth=need).


So we put the following into our application.properties:



Now, if we run the application and point our browser to https://localhost:8443/user, we become informed that the peer cannot be verified and it denies to open our website.


5.3. Client-side Certificate


Now it’s time to create the client-side certificate. The steps we need to take, are pretty much the same as for the server-side certificate we already created.


First, we have to create a certificate signing request:


openssl req -new -newkey rsa:4096 -nodes -keyout clientBob.key -out clientBob.csr

We’ll have to provide information that will be incorporated into the certificate. For this exercise, let’s only enter the common name (CN) – Bob. It’s important as we use this entry during the authorization and only Bob is recognized by our sample application.

我们必须提供将被纳入证书的信息。在这个练习中,我们只输入通用名称(CN) – Bob。这很重要,因为我们在授权过程中使用这个条目,而且只有Bob能被我们的示例应用程序识别。

Next, we need to sign the request with our CA:


openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in clientBob.csr -out clientBob.crt -days 365 -CAcreateserial

The last step we need to take is to package the signed certificate and the private key into the PKCS file:


openssl pkcs12 -export -out clientBob.p12 -name "clientBob" -inkey clientBob.key -in clientBob.crt

Finally, we’re ready to install the client certificate in the browser.


Again, we’ll use Firefox:


  1. Type about:preferences in the address bar
  2. Open Advanced -> View Certificates -> Your Certificates
  3. Click on Import
  4. Locate the Baeldung tutorials folder and its subfolder spring-security-x509/store
  5. Select the clientBob.p12 file and click OK
  6. Input the password for your certificate and click OK

Now, when we refresh our website, we’ll be prompted to select the client certificate we’d like to use:



If we see a welcome message like “Hello Bob!”, that means everything works as expected!

如果我们看到像“Hello Bob!”这样的欢迎信息,那就意味着一切都按预期的那样进行了!这就是我们的工作。


6. Mutual Authentication With XML


Adding X.509 client authentication to an http security configuration in XML is also possible:


    <x509 subject-principal-regex="CN=(.*?)(?:,|$)" 

            <user-service id="userService">
                <user name="Bob" password="" authorities="ROLE_USER"/>

To configure an underlying Tomcat, we have to put our keystore and our truststore into its conf folder and edit the server.xml:


<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" scheme="https" secure="true"
    clientAuth="true" sslProtocol="TLS"
    keystoreType="JKS" keystorePass="changeit"
    truststoreType="JKS" truststorePass="changeit"

Tip: With clientAuth set to “want”, SSL is still enabled, even if the client doesn’t provide a valid certificate. But in this case, we have to use a second authentication mechanism, for example, a login-form, to access the secured resources.


7. Conclusion


In summary, we’ve learned how to create a self-signed CA certificate and how to use it to sign other certificates.


Additionally, we’ve created both, server-side and client-side certificates. Then we’ve presented how to import them into a keystore and a truststore accordingly.


Furthermore, you now should be able to package a certificate together with its private key into the PKCS12 format.


We’ve also discussed when it makes sense to use Spring Security X.509 client authentication, so it is up to you, to decide, whether to implement it into your web application, or not.

我们还讨论了什么时候使用Spring Security X.509客户端认证是有意义的,所以由你来决定是否在你的Web应用中实施它。

And to wrap up, find the source code to this article on Github.