“This is the 14th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

Author: Tangyuan

Personal blog: Javalover.cc

Introduction to the

SpringSecurity has a variety of authentication mechanisms, such as username/password based authentication, OAuth2.0 based authentication (OAuth deprecated)…

There are different authentication modes based on user name and password, for example:

  • Form Login, Form Login authentication (singleton applications such as SpringMVC)
  • Basic Authentication, Basic HTTP Authentication (front-end and back-end separated applications)
  • [Deprecated] Digest Authentication (Deprecated. This Authentication mode is no longer used because its encryption is insecure, such as MD5 encryption. Now the more secure encryption methods are BCrypt, etc.)

This section introduces the first one: form login authentication

directory

  1. Maven configuration
  2. Security configuration
  3. The controller controller
  4. A web interface
  5. Is up and running

The body of the

Before we begin, there are two words to understand

  • Authenticate: logs in to the system using user names or passwords. It’s like a gate into a scenic spot
  • Authorize: is after logging into the system, verify whether the user has the authority to operate a module, this process is authorization; After entering the scenic area, each charging area, only pay the money (have authority), can enter the designated area;

Project background: Spring Boot + SpringMVC + Thymeleaf

The project structure is as follows:

1. The maven configuration:


      
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-boot-demo</artifactId>
        <groupId>com.jalon</groupId>
        <version>0.0.1 - the SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>demo-spring-security-login-form</artifactId>
    <properties>
        <java.version>1.8</java.version>
        <spring.boot.version>2.4.3</spring.boot.version>
        <lombok.version>1.18.16</lombok.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>
Copy the code

2. The security configuration

There are two main parts:

  • Authenticate authentication configuration: configure the user name, password, and role (stored in memory for simplicity).
  • Authorize Configuration: Sets the permissions of each role, that is, the pages that can be accessed
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    // Authentication related operations
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        // Data is not persisted, just stored in memory
        auth.inMemoryAuthentication()
                .withUser("javalover").password(passwordEncoder().encode("123456")).roles("USER")
                .and()
                .withUser("admin").password(passwordEncoder().encode("123456")).roles("ADMIN");
    }

    // Authorize related operations
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            	// The admin page can be accessed only by the admin role
                .antMatchers("/admin").hasRole("ADMIN")
            	The // home page is accessible to both ADMIN and USER
                .antMatchers("/home").hasAnyRole("USER"."ADMIN")
            	// Login page, accessible to all users
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and()
            	// Customize the login form
                .formLogin().loginPage("/login")
            	The second parameter true indicates that the login is successful. The second parameter true indicates that the login is successful. The second parameter false indicates that the login is successful
                .defaultSuccessUrl("/home".true)
            	// Failed to redirect to the login page (e.g. wrong username/password)
                .failureUrl("/login? error=true")
                .and()
                .logout().permitAll()
                .and()
            	// The page will be redirected to if the user does not have the permission to access a page
                .exceptionHandling().accessDeniedPage("/accessDenied");
    }

    // Define a password crypt, which is also Spring's default crypt
    @Bean
    public PasswordEncoder passwordEncoder(a) {
        return newBCryptPasswordEncoder(); }}Copy the code

3. Controller Controller

The controller’s main job is to handle requests, and the following is a typical MVC pattern

@Controller
@Slf4j
public class SecurityController {

    @RequestMapping("/login")
    public String login(a){
        log.info("=== login ===");
        return "login";
    }
    
    @RequestMapping("/home")
    public String home(Model model){
        model.addAttribute("user", getUsername());
        model.addAttribute("role", getAuthority());
        return "home";
    }

    @RequestMapping("/admin")
    public String admin(Model model){
        model.addAttribute("user", getUsername());
        model.addAttribute("role", getAuthority());
        return "admin";
    }
	
    // Permissions are insufficient
    @RequestMapping("/accessDenied")
    public String accessDenied(Model model){
        model.addAttribute("user", getUsername());
        model.addAttribute("role", getAuthority());
        return "access_denied";
    }

    // Get the current login user name
    private String getUsername(a){
        return SecurityContextHolder.getContext().getAuthentication().getName();
    }

    // Get the current logged-in user role: It is possible that a user has multiple roles, so it needs to traverse
    private String getAuthority(a){
        Collection<? extends GrantedAuthority> authorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
        ArrayList<String> list = new ArrayList<>();
        for(GrantedAuthority authority: authorities){
            list.add(authority.getAuthority());
        }
        log.info("= = = authority." + list);
        returnlist.toString(); }}Copy the code

4. The web interface

There are four interfaces:

  • Login. HTML: Login interface, accessible to all
  • Home.html: the main page, accessible to ordinary users and administrators
  • Admin. HTML: administrator page. Only administrators can access the page
  • Access_denied. HTML: Access the denied page. If the permission is insufficient, the page will be redirected. For example, when an ordinary user accesses admin.html

login.html

<! DOCTYPEhtml>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Spring Security</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
</head>
<body>
    <div th:if="${param.error}">
        Invalid username and password.
    </div>
    <div th:if="${param.logout}">
        You have been logged out
    </div>
    <form action="/login" method="post">
        <input name="username" placeholder="Username">
        <input name="password" placeholder="Password">
        <button type="submit">The login</button>
    </form>
</body>
</html>
Copy the code

home.html

<! DOCTYPEhtml>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Spring Security Home</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
</head>
<body>welcome<span th:text="${user}"></span>Your clearance is<span th:text="${role}"></span>
    <a href="admin">Admin page</a>
    <a href="logout">exit</a>
</body>
</html>
Copy the code

admin.html

<! DOCTYPEhtml>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Spring Security Admin</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
</head>
<body>welcome<span th:text="${user}"></span>Your clearance is<span th:text="${role}"></span>
    <a href="logout">exit</a>
</body>
</html>
Copy the code

access_denied.html

<! DOCTYPEhtml>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Access Denied</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
</head>
<body>
    <span th:text="${user}"></span>No permission to access the page your permission is<span th:text="${role}"></span>
    <a href="logout">exit</a>
</body>
</html>
Copy the code

5. Start the system

If you visit http://localhost:8088, the login page is displayed as follows:

Javalover /123456: javalover/123456: Javalover /123456

If you click the admin page, you will be prompted with insufficient permissions, as follows:

Click exit at this time, and return to the login interface again: with a reminder [Logged out]

Finally, log in with the admin account, admin/123456, log in to the home page: you can see that the permission is administrator

Click the admin page and it will normally display:

conclusion

SpringSecurity forms login authentication, in general, there is not a lot of code, because many functions of SpringSecurity are built-in (such as login, logout, insufficient permissions, etc.), we just need to modify some configuration according to their own needs

Source code address: demo-spring-security-login-form