Simple introduction to SpringBoot + Spring Security

This article mainly introduces a simple introduction to SpringBoot + Spring Security

Introduction to Spring Security

Spring Security is not introduced too much here. For details, please refer to Official documents

Let me just talk about the spring security core functions:

  1. Certification (who are you)
  2. Authorization (what can you do)
  3. Attack protection (prevent identity forgery)

Basic environment construction

Here we take spring boot as the basic framework of the project, and I use maven to manage the package, so I'll give the way to integrate Spring Security first

<?xml version="1.0" encoding="UTF-8"?>
<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>jeecg-boot-cloud-study</artifactId>
        <groupId>com.jeecg.cloud</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>jeecg-boot-security</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>
    </dependencies>

</project>

Then establish a Web layer request interface

@RestController
@RequestMapping("/user")
public class UserController {
  @GetMapping
  public String getUsers() {    
    return "Hello Jeecg Spring Security";
  }
}

Next, you can run the project directly and call the interface to see the effect.

Call through web page

We first call the interface through the browser, and directly access http://localhost:8080/user, if the interface can be accessed normally, "Hello Jeecg Spring Security" should be displayed.

But we can't access it normally. The following authentication input box appears

 

This is because in spring boot, the introduced Spring Security dependency and permission control have taken effect automatically. At this time, the interfaces are all protected. We need to verify to access them normally. Spring Security provides a default user. The user name is user, and the password is generated automatically when the project is started.

When we check the Log of project startup, we will find the following Log

Using default security password: 62ccf9ca-9fbe-4993-8566-8468cc33c28c

Of course, the password you see is definitely different from mine. We log in directly with the password in user and startup log.

After the login is successful, you will jump to the normal calling page of the interface.

If you do not want to enable Spring Security at the beginning, you can do the following configuration in the configuration file:

# security enable
security.basic.enabled = false

The login box you just saw is that spring security is provided by the framework itself, which is called httpbasicplogin. Show that it is not what we want on our product. Our front-end is generally used to perform user login authentication by form submission, so we need to customize our own authentication logic.

Custom user authentication logic

Each system must have its own set of user system, so we need to customize our own authentication logic and login interface. Here we need to configure spring security accordingly

package org.jeecg.auth.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()          // Define the login page to go to when a user is required to log in.
                .loginProcessingUrl("/user/login") // Custom login interface
                .and()
                .authorizeRequests()    // Define which URL s need to be protected and which do not
                .anyRequest()        // Any request can be accessed after login
                .authenticated();
    }
}

Custom password encryption and decryption

package org.jeecg.auth.config;

import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

@Component
public class MyPasswordEncoder implements PasswordEncoder {
    @Override
    public String encode(CharSequence charSequence) {
        return charSequence.toString();
    }

    @Override
    public boolean matches(CharSequence charSequence, String s) {
        return s.equals(charSequence.toString());
    }
}

Next, configure the user authentication logic, because we have our own set of user system

package org.jeecg.auth.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

@Component
public class MyUserDetailsService implements UserDetailsService {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        logger.info("User name of the user: {}", username);
        // TODO finds the corresponding password and permission according to the user name

        // Encapsulate user information and return. Parameters are: user name, password, user authority
        User user = new User(username, passwordEncoder.encode("123456"), AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
        return user;
    }
}

We haven't carried out too many checks here. The user name can be filled in at will, but the password must be "123456" in order to log in successfully.

At the same time, you can see that the third parameter of the User object here represents the permissions of the current User. We set it to "admin".

Let's fill in any user here, and then fill in a wrong (not 123456) Password. A verification error will be prompted:

 

At the same time, in the console, the user just filled in at login will also be printed out

Now let's use the correct password to log in. You can find that you will jump to the correct interface call page through verification.

UserDetails

Just now when we wrote MyUserDetailsService, we implemented a method and returned a UserDetails. This UserDetails is the object encapsulating user information, which contains seven methods

public interface UserDetails extends Serializable {
  // Encapsulates permission information
  Collection<? extends GrantedAuthority> getAuthorities();
  // Password information
  String getPassword();
  // Login user name
  String getUsername();
  // Whether the account expires
  boolean isAccountNonExpired();
  // Is the account frozen
  boolean isAccountNonLocked();
  // Whether the account password expires? Generally, some systems with high password requirements will use it. Users are required to reset the password every other period of time
  boolean isCredentialsNonExpired();
  // Is account number available
  boolean isEnabled();
}

When we return the implementation class User of UserDetails, we can set the corresponding parameters through the User construction method

Password encryption and decryption

There is a PasswordEncoder interface in spring security

public interface PasswordEncoder {
  // Encrypt password
  String encode(CharSequence var1);
  // Judge and match the password
  boolean matches(CharSequence var1, String var2);
}

We just need to implement the interface ourselves and configure it in the configuration file.

Tags: Spring Maven Apache SpringBoot

Posted on Sat, 23 May 2020 22:12:20 -0700 by daucoin