How to implement HTTP authentication in Spring Boot?

Posted Jun 16, 202010 min read

HttpBasic authentication has certain limitations and security risks, so it is not used in actual projects. However, sometimes it is more convenient to enable HttpBasic authentication for testing convenience.

So Songge is still here today to talk briefly about HttpBasic authentication in Spring Security.

This article is the 29th in the Spring Security series. Reading the previous article will help you understand this article better:

  1. Dig a big pit, Spring Security starts!

  2. Songge takes you through Spring Security, don t ask how to decrypt the password

  3. Teach you to customize the form login in Spring Security

  4. Spring Security does front and back end separation, let's not do page jumps! All JSON interaction

  5. The authorization operation in Spring Security turned out to be so simple

  6. How does Spring Security store user data in the database?

  7. Spring Security+Spring Data Jpa join forces, security management is only easier!

  8. Spring Boot + Spring Security implements automatic login function

  9. Spring Boot auto login, how to control security risks?

  10. In the microservices project, where is Spring Security better than Shiro?

  11. Two ways for SpringSecurity to customize authentication logic(advanced gameplay)

  12. How to quickly check the login user IP address and other information in Spring Security?

  13. Spring Security automatically kicks off the previous logged-in user, and one configuration is done!

  14. Spring Boot + Vue front and back end separation project, how to kick off the logged-in user?

  15. Spring Security comes with a firewall! You don t know how safe your system is!

  16. What is a session fixation attack? How to prevent session fixed attacks in Spring Boot?

  17. Cluster deployment, how does Spring Security handle session sharing?

  18. Song Ge teaches you how to defend against CSRF attacks in Spring Boot! so easy!

  19. Learn to learn thoroughly! Source code analysis of CSRF defense in Spring Security

  20. Two postures of password encryption in Spring Boot!

  21. How to learn Spring Security? Why must we study in a systematic way?

  22. Spring Security two resource release strategies, don't use it wrong!

  23. Song Ge teaches you how to get started with Spring Boot + CAS single sign-on

  24. Spring Boot's third solution for single sign-on!

  25. Spring Boot+CAS single sign-on, how to connect to the database?

  26. Spring Boot+CAS default login page is too ugly, what should I do?

  27. Test interface with Swagger, how to carry Token in the request header?

  28. Summary of three cross-domain scenarios in Spring Boot

  29. What is HttpBasic


Http Basic authentication is a method of authentication between the Web server and the client. It was originally defined in the HTTP 1.0 specification(RFC 1945). Subsequent information about security can be in the HTTP 1.1 specification(RFC 2616) and HTTP authentication Found in the specification(RFC 2617).

The biggest advantage of HttpBasic is that it is very simple to use, there is no complicated page interaction, only need to carry the corresponding information in the request header to authenticate successfully, and it is a stateless login, that is, the user's login is not recorded in the session information.

The biggest problem of HttpBasic is security, because the user name/password is simply transmitted through Base64 encoding, and it is easy to be sniffed by the tool to expose user information.

Spring Security supports both basic HttpBasic authentication and Http digest authentication. Http digest authentication is based on HttpBasic authentication, which improves information security management, but the code complexity also increases a lot, so Http digest authentication is not used many.

Here, Songge will share with you these two authentication methods in Spring Security.

2.HttpBasic authentication

Let's look at the implementation first, and then analyze its certification process.

First create a Spring Boot project, introduce Web and Spring Security dependencies, as follows:

Next, create a test interface:

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello() {
        return "hello";
    }
}

Then turn on HttpBasic authentication:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .httpBasic();
    }
}

Finally, configure basic user information in application.properties as follows:

spring.security.user.password=123
spring.security.user.name=javaboy

After the configuration is complete, start the project and access the /hello interface. At this time, there will be a pop-up box in the browser, let us enter the username/password information:

At this point we look at the request response header as follows:

As you can see, the browser responded with 401 and also carried a WWW-Authenticate response header. This is used to describe the authentication form. If we are using HttpBasic authentication, the default response header format is shown in the figure.

Next, we enter the user name and password, click Sign In to log in, after successful login, you can successfully access the /hello interface.

We look at the second request, as follows:

As you can see, in the request header, there is an additional Authorization field, the value of this field is Basic amF2YWJveToxMjM=,

amF2YWJveToxMjM= is a string after Base64 encoding. We decoded the string and found that the result is as follows:

String x = new String(Base64.getDecoder().decode("amF2YWJveToxMjM="), "UTF-8");

The decoding result is as follows:

As you can see, this is our username and password information. The username/password is only passed after a simple Base64 encoding, so this authentication method is more dangerous .

Let's briefly summarize the process of HttpBasic authentication:

  1. The browser sends a request saying that it wants to access the /hello interface.
  2. The server returns 401, indicating that it is not authenticated. At the same time, the WWW-Authenticate field is carried in the response header to describe the authentication form.
  3. After receiving the 401 response, the browser pops up a dialog box asking the user to enter the user name/password. After the user enters the user name/password, the browser encodes it with Base64. After the encoding is completed, it is sent to the server.
  4. The server decodes the information from the browser and verifies it. When there is no problem, it responds to the client.

The general process is like this.

3.Http digest authentication

Http digest authentication is basically compatible with HttpBasic authentication, but it is much more complicated. This complexity is not only reflected in the code, but also in the request process.

The most important improvement of Http digest authentication is that he will not send clear text passwords on the network. Its entire certification process is like this:

  1. The browser sends a request saying that it wants to access the /hello interface.
  2. The server returns 401, indicating that it is not authenticated, and carries the WWW-Authenticate field in the response header to describe the authentication form. The difference is that this time the server will calculate a random string and return it to the front end together, which can prevent replay attacks(the so-called replay attack is that someone sniffs your digest information and sends the digest as a password to the server again and again, Add a random string that will change, the generated summary information will change, you can prevent replay attacks), as follows:

At the same time, the field returned by the server also has a qop, indicating the protection level, auth means only authentication; auth-int means to verify the content.

Nonce is a random string generated by the server. This is a string encoded with Base64. After decoding, we found that it is composed of the expiration time and the key. In subsequent requests, the nonce will be sent back to the server intact.

  1. The client selects an algorithm and calculates a summary of the password and other data according to the algorithm, as follows:

It can be seen that more data is sent by the client to the server.

  • nonce is a random string sent from the server.
  • response is the summary information generated.
  • nc indicates that the request can prevent replay attacks at this time.
  • cnonce represents a random string sent by the client to the server.
  1. The server can query the user password based on the user name sent by the client, and then calculate the summary information based on the user password, and then compare the summary information with the summary information sent by the client to confirm the user's identity.

This is the whole process.

In a nutshell, the original user password is replaced by summary information. For security, the summary information will change according to the random string returned by the server. The server also calculates the password summary information according to the user password, and then Compare with the summary information from the client. If there is no problem, the user will be authenticated successfully. Of course, on this basis, some expiration restrictions and replay attack prevention mechanisms are added.

Okay, how should this be implemented in the Spring Security code?

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .csrf()
                .disable()
                .exceptionHandling()
                .authenticationEntryPoint(digestAuthenticationEntryPoint())
                .and()
                .addFilter(digestAuthenticationFilter());
    }

    @Bean
    DigestAuthenticationEntryPoint digestAuthenticationEntryPoint() {
        DigestAuthenticationEntryPoint entryPoint = new DigestAuthenticationEntryPoint();
        entryPoint.setKey("javaboy");
        entryPoint.setRealmName("myrealm");
        entryPoint.setNonceValiditySeconds(1000);
        return entryPoint;
    }
    @Bean
    DigestAuthenticationFilter digestAuthenticationFilter() {
        DigestAuthenticationFilter filter = new DigestAuthenticationFilter();
        filter.setAuthenticationEntryPoint(digestAuthenticationEntryPoint());
        filter.setUserDetailsService(userDetailsService());
        return filter;
    }

    @Override
    @Bean
    protected UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("javaboy").password("123").roles("admin").build());
        return manager;
    }

    @Bean
    PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

}

The configuration is nothing more than two aspects, one is the generation of random strings on the server side, and the other is the verification of client summary information.

  1. First provide an instance of DigestAuthenticationEntryPoint, and configure the server-generated random number generation parameters, such as the nonce validity period(how long it will change), the realm name, and the key required to generate the nonce. The specific generation logic of nonce is in DigestAuthenticationEntryPoint#commence method:

    public void commence(HttpServletRequest request, HttpServletResponse response,

         AuthenticationException authException) throws IOException {
     HttpServletResponse httpResponse = response;
     long expiryTime = System.currentTimeMillis() +(nonceValiditySeconds * 1000);
     String signatureValue = DigestAuthUtils.md5Hex(expiryTime + ":" + key);
     String nonceValue = expiryTime + ":" + signatureValue;
     String nonceValueBase64 = new String(Base64.getEncoder().encode(nonceValue.getBytes()));
     String authenticateHeader = "Digest realm=\"" + realmName + "\", "
             + "qop=\"auth\", nonce=\"" + nonceValueBase64 + "\"";
     if(authException instanceof NonceExpiredException) {
         authenticateHeader = authenticateHeader + ", stale=\"true\"";
     }
     if(logger.isDebugEnabled()) {
         logger.debug("WWW-Authenticate header sent to user agent:"
                 + authenticateHeader);
     }
     httpResponse.addHeader("WWW-Authenticate", authenticateHeader);
     httpResponse.sendError(HttpStatus.UNAUTHORIZED.value(),
         HttpStatus.UNAUTHORIZED.getReasonPhrase());

    }

In this code, first get the expiration time, then calculate the message digest for the expiration time and key, and then use the nonce and message digest together as the value to calculate a Base64 encoded character, and then write the encoded character back to the front end .

  1. Configure the DigestAuthenticationFilter filter, which is mainly used to process front-end requests. The source code of the filter is relatively long, I will not post it here. A core idea is to get the summary information requested by the user from the front end, and the server also calculates a summary based on the continuous information, and then based on the summary information passed on Compare, and then confirm the user's identity.

After the configuration is complete, restart the server for testing.

The test effect is actually the same as HttpBasic authentication. All the changes are just the implementation behind. The user experience is the same.

  1. Summary

Although the effect of Http digest authentication is safer than HttpBasic, in fact, as you can see, the security problems solved by the entire process are actually very limited. And the code is also a lot of trouble, so this authentication method is not widely popular.

The Http authentication partners can be used as an understanding. Some of the ideas inside are quite interesting and can inspire us to solve other problems. For example, for solutions to replay attacks, if we want to defend ourselves against replay attacks, we You can refer to the implementation ideas here.

Okay, if your friends are rewarded, remember to watch and encourage Songge~