This article will take about 10 minutes to read

preface

The motivation of this series of lick blocks is to promote Spring Security in the Chinese community. Because Spring Security makes sense for almost all Spring applications, we will start our tutorial with Spring Security in the first installment. At the same time, we also produced a 10-minute video explanation for each period, hoping to make up for the confusion brought to readers by only using words and pictures to describe a technical knowledge point.

Finally, at the time this series was written, we were using SpringBoot version 1.5; The Security version is 5. If the normal operation and expected results cannot be obtained due to version differences, you can give us feedback by commenting on the private message. thank you

The first phase quickly adds Spring Security to Spring Boot applications

This issue’s to-do list

  1. Quickly initialize a Spring Boot project
  2. How do I add memory-based user authentication
  3. How do I add role-based access control logic

1. Quickly initialize a Spring Boot project

We recommend using the project initializer provided by Spring for beginners unfamiliar with Maven’s Pom.xml authoring and Spring’s various starter dependencies. IO/Our goal is to initialize a Springboot-based Web application with Security components. Therefore, in the dependency component section of the Web interface of the tool, you need to type and select Web, Security, and Thymeleaf component dependencies. After clicking Generate, the browser will automatically download a project project package.

After decompressing the code, importing through IDEA gives you a basic SpringBoot application that already includes Security. Run Demoapplication. Java, after the application is started on the console, access the host port 127.0.0.1:8080 through the browser. If you see the login dialog box prompting you to enter the user name and password, it means that Security has been successfully loaded into the application.

2. Add memory-based user authentication

Distinction between authentication and access control

Our second task was to configure the Security framework to correctly retrieve user information for login checks. We chose to write this configuration through the JavaConfig mode class, which we call WebSecurityConfig, and type the following code.

@ EnableWebSecurity / / configuration annotation public class WebSecurityConfig extends WebSecurityConfigurerAdapter { Inject a new userDetailsServiceBean@bean public UserDetailsServiceuserDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("user").password("password").roles("USER").build());
        returnmanager; }}Copy the code

The main thing we did in the code was inject oneThe component. So what is?

UserDetailsService and populated UserDetails

UserDetails was the first important concept we encountered. From Spring Security’s point of view, UserDetails is like the concept of users and accounts that we design our own system. It contains the username, password, and corresponding permissions.

public interface UserDetails extends Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();

    String getPassword();

    String getUsername();

    boolean isAccountNonExpired();

    boolean isAccountNonLocked();

    boolean isCredentialsNonExpired();

    boolean isEnabled();
}
Copy the code

The UserDetailsSevice service describes how to obtain inventory user information in the system.

public interface UserDetailsService {
	UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}}
Copy the code

Here we can simply assume that after we input the user name and password, the framework will use the implementation class of UserDetailsService to find and verify whether the user name and password entered in front of the user are correct. If they are correct, the framework will return UserDetails to complete the login operation. The Security pattern provides many ways to implement user information management services, such as database-based and LDAP-based. We currently used is the most simple memory based InMemoryUserDetailsManager user management is realized.

    @Bean
    public UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("user").password("password").roles("USER").build());
        return manager;
    }
Copy the code

If Sping Security5 is used, the string in the Password section is. Password (“{noop}password”). Otherwise an exception might be thrown.

After the application is restarted, re-access the test application at http://127.0.0.1:8080/. After you enter the user name and password, a 404 error is displayed indicating that the page to be accessed does not exist. This at least proves that the login logic is done, and a simple controller and page template can do the second task later. Controller code MainController

@Controller
public class MainController {
    @RequestMapping("/")
    public String root() {
        return "index";
    }
Copy the code

Page template code index.html

<! DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
    <title>Hello Spring</title>
    <meta charset="utf-8" />
    <link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
</head>
<body>
    <h1>Hello Spring</h1>
</body>
</html>
Copy the code

Once logged in, we should see the hello page we expect.

3. How to add role-based access control logic

Having completed authentication, one of Spring Security’s two main concerns, we are now ready to implement a simple access control logic. First, let’s do a simple design for the goal of the current task: We’ll write two path pages in the MainController, a “path” that doesn’t require access control and a “\user” path that requires login control.

Writing controller

First, we complete the MainContoller code according to the design, and add a new URL and the corresponding view template. The user.html pair simply copy the index. HTML and change the content to Welcome user. MainController .java

@Controller
public class MainController {
    @RequestMapping("/")
    public String root() {
        return "index";
    }
    @RequestMapping("/user")
    public String userIndex() {
        return "user"; }}Copy the code

user.html

<! DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
    <title>Welcome User</title>
    <meta charset="utf-8" />
    <link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
</head>
<body>
    <h1>Welcome User</h1>
</body>
</html>
Copy the code

Write access control configurations

Our configuration class, WebSecurityConfig, is provided by the inheritance frameworkThere is an important configuration scheme. Let’s take a look at the default implementation provided by the framework:


	protected void configure(HttpSecurity http) throws Exception {
		logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");
		http
			.authorizeRequests()
				.anyRequest().authenticated()
				.and()
			.formLogin().and()
			.httpBasic();
	}
Copy the code

An HttpSecurity configuration has three main points:

  1. Manage path access control under authorizeRequests();
  2. FormLogin () manages the login form configuration;
  3. HttpBasic () is configured based on Http authentication. The latter two points are not our focus, our goal is to configure access control for the path, so we need to override this method in our own configuration class:
@Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() // The corresponding URL of inde.html allows the assigned person to access.antmatchers ("/".antmatchers ().permitall () // user.html"/user").hasRole("USER")
                .and()
                .formLogin();
    }
Copy the code

We are using hasRole() role-based authentication criteria. Let me review the user record code we added earlier in the user authentication section. The user we added also contains a role of user, which is checked for matching authorization information during access control. This is available if you are using a version below Spring Security 4

manager.createUser(User.withUsername("user").password("password").roles("USER").build());
Copy the code

If use is more than 5 version, because in the Spring Security through configuration PasswordEncoder correct password encryption operation. The User can proceed withDefaultPasswordEncoder (), or may report errors framework.

manager.createUser(
    User.withDefaultPasswordEncoder()
        .username("user")
        .password("password")
        .roles("USER")
        .build());
Copy the code

User. WithDefaultPasswordEncoder () is a only used in the sample application method, because the Spring Security 5 on the mechanism of the component is adjusted, Using the previous code to generate user information makes it impossible to determine which PasswordEncoder to use. Specific details will be explained in a separate topic later. Thank you for asking the question of string feedback.

Restart the application, first type/path, the application does not prompt us for any login dialog box, we see Hello Spring title.

Then we type the \user path, because access control checks that we haven’t completed the login operation and redirects us to the login page to complete the login operation. Finally, after we complete the username and input, we get access to the target /user page because the user role is as configured as expected.

At the end

In this installment, we’ve done the simplest implementation and configuration of two of SpringSecurity’s most important features: user authentication and access control. In the next installment, we will explain the process of user authentication. See you next time.