Chapter 01- Spring Security

Section 01 – introduction

Spring Security is a spring-based Security Framework. Spring Security provides a comprehensive Security solution, and handles authentication and authorization in Web Request and Method. Based on Spring Framework, Spring Security takes advantage of the nontrivial DI and AOP features to provide declarative secure access control for applications, and is a lightweight framework that integrates well with Spring and Spring MVC

Section 02- Core functions

  1. Certification (Who are you?)
  2. What can you do?

Section 3 – principle

Implement authentication and authorization based on Servlet Filter AOP

Chapter 02- Best Practices

Section 01- Login with system custom users and custom users in YML

  1. Creating a Maven project
  2. Add dependencies,SpringBoot Web stater and security-stater
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-parent</artifactId>
    <version>2.1.5.RELEASE</version>
</parent>

<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>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
Copy the code

3. Create a boot class for SpringBoot

@SpringBootApplication
public class SecurityApplication {

    public static void main(String[] args) { SpringApplication.run(SecurityApplication.class,args); }}Copy the code

4. Create the Controller package and Contrller controller

@RestController
public class HelloSecurityController {

    @GetMapping("/security")
    public String helloSecurity(a){
        return "Hello Spring Security!"; }}Copy the code

5. Start SecurityApplication and the console generates the password, as shown in the following figure

Enter in the browser address barhttp://localhost:8080/

Enter the user name user and the password generated by the console to log in and access the HelloSecurityController

If you enter an incorrect password, you will be prompted accordingly

6. The preceding user names and passwords are automatically generated by the system. If you want to customize a user name and password, you need to configure the user name and password in the configuration file

spring:
  security:
    user:
      name: admin
      password: admin
Copy the code

7. Disable login authentication to modify the startup class. {} can contain multiple configuration classes

@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
public class SecurityApplication {

    public static void main(String[] args) { SpringApplication.run(SecurityApplication.class,args); }}Copy the code

Section 02- Login with a user set in memory

Inheritance WebSecurityConfigurerAdapter, rewrite the configure method to control the content of the safety management, will rewrite the class manage by the Spring IOC, can customize the authentication function, Overrides require two annotations @configuration and @enableWebSecurity

@Configuration// Indicates that this class is a configuration class, and the return value is a Java object, managed by SpringIOC, which is equivalent to a configuration XML file
@EnableWebSecurity // Enables the SpringSecurity framework function
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        PasswordEncoder pe = passwordEncoder();

        // Set the memory user name and password
        auth.inMemoryAuthentication().withUser("IronMan").password(pe.encode("12345")).roles();
        auth.inMemoryAuthentication().withUser("SpiderMan").password(pe.encode("12345")).roles();
        auth.inMemoryAuthentication().withUser("Thor").password(pe.encode("thor")).roles();
    }

    // Password encryption class, which is managed by SpringIOC and whose ID is passwordEncoder by default
    @Bean
    public PasswordEncoder passwordEncoder(a){
        // Implement password encryption
        return newBCryptPasswordEncoder(); }}Copy the code

Start shut before start class on the contents of the exclude, after the success of the launch using set user name password to log in the system, if the change in the configuration class set password encryption without complains “Java. Lang. IllegalArgumentException: There is no PasswordEncoder mapped for the ID “null” “

Section 03- Role-based authentication

Modify the MyWebSecurityConfig class in the config package to give the user a role as follows:

/** * prePostEnabled = true Indicates that it can be used@PreAuthorizeAnnotations and@PostAuthorizeMethod level annotations */
@Configuration// Indicates that this class is a configuration class, and the return value is a Java object, managed by SpringIOC, which is equivalent to a configuration XML file
@EnableWebSecurity // Enables the SpringSecurity framework function
@EnableGlobalMethodSecurity(prePostEnabled = true) // Enable method-level security controls
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        PasswordEncoder pe = passwordEncoder();

        // Set the memory user name and password, and set the role. A user can have multiple roles
        auth.inMemoryAuthentication().withUser("IronMan").password(pe.encode("12345")).roles("admin");
        auth.inMemoryAuthentication().withUser("SpiderMan").password(pe.encode("12345")).roles("user");
        auth.inMemoryAuthentication().withUser("Thor").password(pe.encode("thor")).roles("user"."admin");
    }

    // Password encryption class, which is managed by SpringIOC and whose ID is passwordEncoder by default
    @Bean
    public PasswordEncoder passwordEncoder(a){
        // Implement password encryption
        return newBCryptPasswordEncoder(); }}Copy the code

Modify HelloSecurityController to define the role access path

@RestController
public class HelloSecurityController {

    @GetMapping("/security")
    public String sayHello(a){
        return "Authentication using in-memory user information";
    }

    // Specify methods accessible to both user and admin
    @GetMapping("/hello")
    @PreAuthorize(value = "hasAnyRole('admin','user')")
    public String helloUserAndAdmin(a){
        return "Both user and admin roles are accessible";
    }

    @GetMapping("/admin")
    @PreAuthorize(value = "hasAnyRole('admin')")
    public String helloAdmin(a){
        return "Only Admin can access"; }}Copy the code

Start the application and use IronMan/12345 to access /helloAccess the /admin pathRestart Tomcat using Thor/ Thor to access /helloTo access/adminDifferent roles have access to different paths

Section 04- JDBC-based user authentication

First modify pom.xml to add MySQL dependency and JPA

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.18</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
Copy the code

Create the entity class UserInfo and add the get/set methods

@Entity
public class UserInfo {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String username;
    private String password;
    private String role;
}
Copy the code

Create persistence layer UserInfoDao, inherit JpaRepository, define method findByUsername(String username)

public interface UserInfoDao extends JpaRepository<UserInfo.Long>{

    // Query the database as username
    UserInfo findByUsername(String username);
}
Copy the code

Create the Service layer UserInfoService interface and create the UserInfoServiceImpl implementation class to implement the interface

public interface UserInfoService {

    UserInfo findUserInfo(String username);
}
Copy the code

Don’t forget the @service annotation

@Service public class UserInfoServiceImpl implements UserInfoService { @Autowired private UserInfoDao userInfoDao; @Override public UserInfo findUserInfo(String username) { return userInfoDao.findByUsername(username); }}Copy the code

Configure the application. The properties

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test? useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root

spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
spring.jpa.database=mysql
InnoDB engine is used when creating tables. Myisam is used by default
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
Copy the code

Starting the application at this point creates the user_INFO table in the database, and then initializes the data in the user_INFO table and creates the JDBCInit class under the init package

@Component
public class JDBCInit {

    @Autowired
    private UserInfoDao userInfoDao;

    @PostConstruct
    public void init(a){

        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        UserInfo user1 = new UserInfo();
        user1.setUsername("IronMan");
        user1.setPassword(passwordEncoder.encode("12345"));
        user1.setRole("admin");

        userInfoDao.save(user1);

        UserInfo user2 = new UserInfo();
        user2.setUsername("thor");
        user2.setPassword(passwordEncoder.encode("12345"));
        user2.setRole("user"); userInfoDao.save(user2); }}Copy the code

Next, create MyUserDetailService, which inherits the UserDetailService from the framework package and acts like storing user role information

@Component("myUserDetailService")
public class MyUserDetailService implements UserDetailsService {

    @Autowired
    private UserInfoService userInfoService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserInfo userInfo = null;
        User user = null;
        if(username ! =null){
            userInfo = userInfoService.findUserInfo(username);
            if(userInfo ! =null){
                List<GrantedAuthority> grantedAuthorityList = new ArrayList<>();
                GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_"+userInfo.getRole());
                grantedAuthorityList.add(authority);
                // Create the User class, the User class in the framework
                user = newUser(userInfo.getUsername(),userInfo.getPassword(),grantedAuthorityList); }}returnuser; }}Copy the code

Modify MyWebSecurityConfig to remove all code that saves information to memory

/** * prePostEnabled = true Indicates that it can be used@PreAuthorizeAnnotations and@PostAuthorizeMethod level annotations */
@Configuration// Indicates that this class is a configuration class, and the return value is a Java object, managed by SpringIOC, which is equivalent to a configuration XML file
@EnableWebSecurity // Enables the SpringSecurity framework function
@EnableGlobalMethodSecurity(prePostEnabled = true) // Enable method-level security controls
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailService myUserDetailService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailService).passwordEncoder(newBCryptPasswordEncoder()); }}Copy the code

The HelloSecurityController code remains the same, start the application, login with IronMan/12345, and access /hello, /admin

Log in with Thor /12345 and access /hello, /admin