[Spring Security + OAuth2 + JWT start to practice] 4. System configuration user-defined login page

Keywords: Programming Spring Lombok Apache Java

brief introduction

Previously, the default authentication process of spring security was used to process user-defined data and password encryption, but in the actual development, it must be to use the page developed by itself, the business processing of login success and failure, etc.

The personalization configuration is completed in the browser security config of the spring security browser project.

Custom login page

Create login page

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Standard landing page</title>
</head>
<body>
<h2>Standard landing page</h2>
<h3>Form login</h3>
<form action="/authentication/form" method="post">
    <table>
        <tr>
            <td>User name:</td>
            <td><input type="text" name="username"></td>
        </tr>
        <tr>
            <td>Password:</td>
            <td><input type="password" name="password"></td>
        </tr>
        <tr>
            <td colspan="2">
                <button type="submit">Sign in</button>
            </td>
        </tr>
    </table>
</form>
</body>
</html>

Note the path here: acrion="/authentication/form"; the path is custom
The UsernamePasswordAuthenticationFilter, by default, processes login requests from the / login path. The following configuration solves this problem

public UsernamePasswordAuthenticationFilter() {
  super(new AntPathRequestMatcher("/login", "POST"));
}

 

Override the configure method in the BrowserSecurityConfig class

@Override
protected void configure(HttpSecurity http) throws Exception {
    //To configure
}
package com.spring.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //To configure
        http
                .formLogin()
                .loginPage("/signIn.html")//Login page path
                // Process login request path
                .loginProcessingUrl("/authentication/form")
                .and()
                .authorizeRequests() // Authorized configuration
                //Path without authentication
                .antMatchers("/signIn.html").permitAll()
                .anyRequest() // All requests
                .authenticated() // All need certification
                .and().csrf().disable();
    }
}

 

Start project test: http://127.0.0.1:8080/hello

Handling different types of requests

What we are doing is that there may be multiple login pages for a reusable framework. Now we can solve this problem

Create a custom Controller in the spring security browser project

package com.spring.security;

import com.spring.security.support.SimpleResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@RestController
public class BrowserSecurityController {
    // Encapsulates the tool class that causes the jump request, and gets it from the session
    private RequestCache requestCache = new HttpSessionRequestCache();

    // spring's tool class: encapsulates all jump behavior policy classes
    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();


    /**
     * Jump here when identity authentication is required
     *
     * @param request
     * @param response
     * @return
     * @throws IOException
     */
    @RequestMapping("/authentication/require")
    @ResponseStatus(code = HttpStatus.UNAUTHORIZED)
    public SimpleResponse requirAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException {
        SavedRequest savedRequest = requestCache.getRequest(request, response);
        // If there is a request to initiate authentication
        // Should spring store information somewhere before jumping?
        if (savedRequest != null) {
            String targetUrl = savedRequest.getRedirectUrl();
            System.out.println("Request to trigger jump:" + targetUrl);
            // If html request, go to login page
            if (StringUtils.endsWithIgnoreCase(targetUrl, ".html")) {
                redirectStrategy.sendRedirect(request, response, "Fill in the page to jump here without writing, etc. read from the configuration file");
            }
        }
        // Otherwise, the json string to be authenticated will be returned
        return new SimpleResponse("Access to services requires authentication!");
    }
}

Create return value class in spring security browser project

package com.spring.security.support;

import lombok.Data;

@Data
public class SimpleResponse {
    private Object content;

    public SimpleResponse(Object content) {
        this.content = content;
    }
}

Solve the user-defined jump login page, read yml

Modify the spring security demo project application.yml

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1/auto_test?useUnicode=yes&characterEncoding=UTF-8&useSSL=false
    username: root
    password: 123456
hk:
  security:
    browser:
      loginPage: /demoLogin.html  #Login page

As for the encapsulation of system configuration, the outermost encapsulation of security properties includes browserproperties, validatecodeproperties, oauth2properties;

Create a new SecurityProperties class in the spring security core project:

package com.spring.security.properties;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * Security attribute
 */
@Data
@ConfigurationProperties(prefix = "hk.security")
public class SecurityProperties {

    private BrowserProperties browser = new BrowserProperties();

}

Same as BrowserProperties class

package com.spring.security.properties;

import lombok.Data;

/**
 * Browser properties
 */
@Data
public class BrowserProperties {

    /**
     * Login page default login page signIn.html
     */
    private String loginPage = "/signIn.html";
}

For the above configuration to take effect, you need to add a SecurityCoreConfig class

New in core project:

package com.spring.security.config;

import com.spring.security.properties.SecurityProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**
 * Security core configuration
 * SecurityProperties  Take effect
 */
@Configuration
@EnableConfigurationProperties(SecurityProperties.class)
public class SecurityCoreConfig {
}

Modifying BrowserSecurityController to read system configuration

package com.spring.security;

import com.spring.security.properties.SecurityProperties;
import com.spring.security.support.SimpleResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@RestController
public class BrowserSecurityController {
    // Encapsulates the tool class that causes the jump request, and gets it from the session
    private RequestCache requestCache = new HttpSessionRequestCache();

    // spring's tool class: encapsulates all jump behavior policy classes
    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    @Autowired
    private SecurityProperties securityProperties;

    /**
     * Jump here when identity authentication is required
     *
     * @param request
     * @param response
     * @return
     * @throws IOException
     */
    @RequestMapping("/authentication/require")
    @ResponseStatus(code = HttpStatus.UNAUTHORIZED)
    public SimpleResponse requirAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException {
        SavedRequest savedRequest = requestCache.getRequest(request, response);
        // If there is a request to initiate authentication
        // Should spring store information somewhere before jumping?
        if (savedRequest != null) {
            String targetUrl = savedRequest.getRedirectUrl();
            System.out.println("Request to trigger jump:" + targetUrl);
            // If html request, go to login page
            if (StringUtils.endsWithIgnoreCase(targetUrl, ".html")) {
                redirectStrategy.sendRedirect(request, response, securityProperties.getBrowser().getLoginPage());
            }
        }
        // Otherwise, the json string to be authenticated will be returned
        return new SimpleResponse("Access to services requires authentication!");
    }
}

Now the system configuration login page of demo project is: demoLogin.html

To create a new demoLogin.html page for a demo project:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>demo Login page</title>
</head>
<body>
<h2>demo Login page</h2>
</body>
</html>

Modifying BrowserSecurityConfig class does not block login page

package com.spring.security;

import com.spring.security.properties.SecurityProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SecurityProperties securityProperties;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //To configure
        http
                .formLogin()
                .loginPage("/authentication/require")//Login page path
                // Process login request path
                .loginProcessingUrl("/authentication/form")
                .and()
                .authorizeRequests() // Authorized configuration
                //Path without authentication
                .antMatchers("/authentication/require","/signIn.html",securityProperties.getBrowser().getLoginPage()).permitAll()
                .anyRequest() // All requests
                .authenticated() // All need certification
                .and().csrf().disable();
    }
}

Launch project access: http://127.0.0.1:8080/hello

Visit: http://127.0.0.1:8080/index.html

Comment out the system configuration:

#hk:
#  security:
#    browser:
#      loginPage: /demoLogin.html  #Login page

Restart project access: http://127.0.0.1:8080/index.html

Posted by phbock on Mon, 02 Mar 2020 01:33:07 -0800