Detailed explanation of integrating SpringSecurity with SpringBoot based on madness learning [~]

Posted by Bill_Draving on Mon, 29 Nov 2021 14:25:51 +0100

Spring security

Official documents:
Official documents

jurisdiction:

  • Functional authority
  • Access rights
  • Menu permissions

We used interceptors and filters to implement these permissions, and used a lot of native code.

Now you can use the security framework

The core of security framework is to assign permissions to roles, not to corresponding users, and users only need to obtain corresponding roles to obtain corresponding permissions

1. Create a new module

Just check the spring web dependency

Import themleaf dependency in poem

themleaf official document:

Official documents

 <!-- thymeleaf Template -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-java8time</artifactId>
        </dependency>

2. Import static resources

3. Write Controller layer

package com.zhen.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class RouterController {

    @RequestMapping("/")
    public String index(){
        return "index";
    }

    @RequestMapping("/toLogin")
    public String toLogin(){
        return "views/login";
    }

    //In this way, code reuse can be realized. Writing one is equivalent to writing three
    @RequestMapping("/level1/{id}")
    public String level1(@PathVariable("id") int id){

        return "views/level1/"+id;              // Note "/"
    }

 @RequestMapping("/level2/{id}")
    public String level2(@PathVariable("id") int id){

        return "views/level2/"+id;
    }
 @RequestMapping("/level3/{id}")
    public String level3(@PathVariable("id") int id){

        return "views/level3/"+id;
    }

}

ps. when writing a map, we can write one in a simple way and map three

​ @RequestMapping("/level1/{id}")

​ return "views/level1/"+id;

4. Understanding spring security

Spring Security is the security framework for the spring project and the default technology selection of the Spring Boot underlying security module. It can realize powerful Web security control. For security control, we only need to introduce the Spring Boot starter security module and configure a small amount to realize powerful security management!

Several important categories:

  • WebSecurityConfigurerAdapter: custom Security policy

  • AuthenticationManagerBuilder: custom authentication policy

  • @Enable WebSecurity: enable WebSecurity mode

The two main goals of Spring Security are "authentication" and "authorization" (access control).

Authentication

Authentication is about verifying your credentials, such as user name / user ID and password, to verify your identity.

Authentication is usually done by user name and password, sometimes in combination with authentication factors.

Authorization

Authorization occurs after the system successfully verifies your identity, and will eventually grant you full access to resources (such as information, files, databases, funds, locations, almost anything).

This concept is universal, not just in Spring Security.

Refer to the official website: https://spring.io/projects/spring-security

5. Everyone can access the test environment we just wrote. Now we use Spring Security to add authentication and authorization functions

1. Introduce Spring Security module

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

2. Write Spring Security configuration class

Refer to the official website: https://spring.io/projects/spring-security

Find the relevant documents of your corresponding version

  • The following error occurs after writing according to normal,
There is no Passwordencoder mapped for the id " null
  • Note that in the new version of spring boot, we need password encryption to use this method
.passwordEncoder(new BCryptPasswordEncoder())
  • So our complete configuration class is
package com.zhen.config;

import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;


@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //to grant authorization
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        //The home page is accessible to everyone
        //The function page can only be accessed by the corresponding authorized person

        // Rules for requesting authorization
        http.authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/level1/**").hasRole("vip1")
                .antMatchers("/level2/**").hasRole("vip2")
                .antMatchers("/level3/**").hasRole("vip3");


        //Without permission, we let him default to the login interface and need to open the login page
        //Automatically entered "/ login"
        http.formLogin();
    }


    //authentication

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

        //Normally, it should be read from the database
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())          //Add password encryption function
                .withUser("zhen").password(new BCryptPasswordEncoder().encode("12345")).roles("vip1", "vip2")
                //Note that roles should correspond to the hasRole above!!
                .and()
                .withUser("root").password(new BCryptPasswordEncoder().encode("12345")).roles("vip2", "vip3", "vip3");
    }
}

6. Enter our web page to verify the relevant permissions. It is found that there is no problem, and then we need to realize our logout function

1. First, we need to write the logout button in the front of the web page

<a class="item" th:href="@{/logout}">
   <i class="address card icon"></i> cancellation
</a>

2. Enable the logoff function in securityconfigger

//Enable logoff function
        http.logout();

When we went to test, we found that after logging out, we would jump to the login interface.

3. Then we want him to log out and return to our first page

       //Turn on the logout function and jump to the home page
        http.logout().logoutSuccessUrl("/");

Test ok!

But we found that no matter what permissions our login account has, he can see the page. We need to make further corrections. The corresponding user can only see the content with the corresponding permission

4. Improvement of user authority display content

We need to combine some functions in thymeleaf

sec: authorize = "isAuthenticated()": whether to authenticate login

  • Import related dependencies in poem

    <!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity5 -->
    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        <version>3.0.4.RELEASE</version>
    </dependency>
    
    

Modify front page

  • Import namespace

    xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"
    
  • Modify the navigation bar and add authentication judgment

    <!--Login and logout-->
    <div class="right menu">
    
       <!--If you are not logged in-->
       <div sec:authorize="!isAuthenticated()">
           <a class="item" th:href="@{/login}">
               <i class="address card icon"></i> Sign in
           </a>
       </div>
    
       <!--If logged in-->
       <div sec:authorize="isAuthenticated()">
           <a class="item">
               <i class="address card icon"></i>
              user name:<span sec:authentication="principal.username"></span>
              Role:<span sec:authentication="principal.authorities"></span>
           </a>
       </div>
    
       <div sec:authorize="isAuthenticated()">
           <a class="item" th:href="@{/logout}">
               <i class="address card icon"></i> cancellation
           </a>
       </div>
    </div>
    
  • Complete our role certification fast

    <!-- sec:authorize="hasRole('vip1')" -->
    <div class="column" sec:authorize="hasRole('vip1')">
       <div class="ui raised segment">
           <div class="ui">
               <div class="content">
                   <h5 class="content">Level 1</h5>
                   <hr>
                   <div><a th:href="@{/level1/1}"><i class="bullhorn icon"></i> Level-1-1</a></div>
                   <div><a th:href="@{/level1/2}"><i class="bullhorn icon"></i> Level-1-2</a></div>
                   <div><a th:href="@{/level1/3}"><i class="bullhorn icon"></i> Level-1-3</a></div>
               </div>
           </div>
       </div>
    </div>
    
    <div class="column" sec:authorize="hasRole('vip2')">
       <div class="ui raised segment">
           <div class="ui">
               <div class="content">
                   <h5 class="content">Level 2</h5>
                   <hr>
                   <div><a th:href="@{/level2/1}"><i class="bullhorn icon"></i> Level-2-1</a></div>
                   <div><a th:href="@{/level2/2}"><i class="bullhorn icon"></i> Level-2-2</a></div>
                   <div><a th:href="@{/level2/3}"><i class="bullhorn icon"></i> Level-2-3</a></div>
               </div>
           </div>
       </div>
    </div>
    
    <div class="column" sec:authorize="hasRole('vip3')">
       <div class="ui raised segment">
           <div class="ui">
               <div class="content">
                   <h5 class="content">Level 3</h5>
                   <hr>
                   <div><a th:href="@{/level3/1}"><i class="bullhorn icon"></i> Level-3-1</a></div>
                   <div><a th:href="@{/level3/2}"><i class="bullhorn icon"></i> Level-3-2</a></div>
                   <div><a th:href="@{/level3/3}"><i class="bullhorn icon"></i> Level-3-3</a></div>
               </div>
           </div>
       </div>
    </div>
    

5. Remember the realization of my function

  • Enable function (enabled in SecurityConfig)

          //Enable remember me function
            http.rememberMe();
    

    We refresh the startup project and test it. We find that there is an additional remember me function on the login page!

    Just log in and bring this cookie.

  • When this request is submitted, we also need to verify the processing,

http.formLogin()
  .usernameParameter("username")
  .passwordParameter("password")
  .loginPage("/toLogin")
  .loginProcessingUrl("/login"); // Login form submission request
  • Add the remember me multi selection box on the login page

    <input type="checkbox" name="remember"> Remember me
    
  • Then we need to verify the processing at the back end!

      //Enable remember me function
            //Customize and remember my parameters!
            http.rememberMe().rememberMeParameter("remember");
    

be accomplished!

Attach the last complete code

1. Complete configuration class (SecurityConfig)

package com.zhen.config;

import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;


@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //to grant authorization
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        //The home page is accessible to everyone
        //The function page can only be accessed by the corresponding authorized person

        // Rules for requesting authorization
        http.authorizeRequests()
                .antMatchers("/index","/").permitAll()
                .antMatchers("/level1/**").hasRole("vip1")
                .antMatchers("/level2/**").hasRole("vip2")
                .antMatchers("/level3/**").hasRole("vip3");


        //Without permission, we let him default to the login interface and need to open the login page
                 //Automatically entered "/ login"
        http.formLogin()
                .usernameParameter("username")
                .passwordParameter("password")
                .loginPage("/toLogin")
                .loginProcessingUrl("/usr/login"); // Login form submission request

        //Turn on the logout function and jump to the home page
        http.logout().logoutSuccessUrl("/toLogin");

        //Enable remember me function
        //Customize and remember my parameters!
        http.rememberMe().rememberMeParameter("remember");
    }


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


        //Normally, it should be read from the database
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())          //Add password encryption function
                .withUser("zhen").password(new BCryptPasswordEncoder().encode("12345")).roles("vip1", "vip2")
                //Note that roles should correspond to the hasRole above!!
                .and()
                .withUser("root").password(new BCryptPasswordEncoder().encode("12345")).roles("vip2", "vip3", "vip3");
    }

}

2. Complete login

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <title>Sign in</title>
    <!--semantic-ui-->
    <link href="https://cdn.bootcss.com/semantic-ui/2.4.1/semantic.min.css" rel="stylesheet">
</head>
<body>

<!--Main container-->
<div class="ui container">

    <div class="ui segment">

        <div style="text-align: center">
            <h1 class="header">Sign in</h1>
        </div>

        <div class="ui placeholder segment">
            <div class="ui column very relaxed stackable grid">
                <div class="column">
                    <div class="ui form">
                        <form th:action="@{/usr/login}" method="post">
                            <div class="field">
                                <label>Username</label>
                                <div class="ui left icon input">
                                    <input type="text" placeholder="Username" name="username">
                                    <i class="user icon"></i>
                                </div>
                            </div>
                            <div class="field">
                                <label>Password</label>
                                <div class="ui left icon input">
                                    <input type="password" name="password">
                                    <i class="lock icon"></i>
                                </div>
                            </div>
                            <input type="submit" class="ui blue submit button"/>
                            <input type="checkbox" name="remember"> Remember me
                        </form>
                    </div>
                </div>
            </div>
        </div>

        <div style="text-align: center">
            <div class="ui label">
                </i>register
            </div>
            <br><br>
            <small>329179436@qq.com</small>
        </div>
        <div class="ui segment" style="text-align: center">
            <h3>Spring Security Study by Zhen</h3>
        </div>
    </div>


</div>

<script th:src="@{/qinjiang/js/jquery-3.1.1.min.js}"></script>
<script th:src="@{/qinjiang/js/semantic.min.js}"></script>

</body>
</html>

3. Complete index

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <title>home page</title>
    <!--semantic-ui-->
    <link href="https://cdn.bootcss.com/semantic-ui/2.4.1/semantic.min.css" rel="stylesheet">
    <link th:href="@{/qinjiang/css/qinstyle.css}" rel="stylesheet">
</head>
<body>

<!--Main container-->
<div class="ui container">

    <div class="ui segment" id="index-header-nav" th:fragment="nav-menu">
        <div class="ui secondary menu">
            <a class="item" th:href="@{/index}">home page</a>

            <!--Login and logout-->
            <div class="right menu">

                <!--If you are not logged in-->
                <div sec:authorize="!isAuthenticated()">
                    <a class="item" th:href="@{/toLogin}">
                        <i class="address card icon"></i> Sign in
                    </a>
                </div>

                <!--If logged in-->
                <div sec:authorize="isAuthenticated()">
                    <a class="item">
                        <i class="address card icon"></i>
                        user name:<span sec:authentication="principal.username"></span>
                        Role:<span sec:authentication="principal.authorities"></span>
                    </a>
                </div>

                <div sec:authorize="isAuthenticated()">
                    <a class="item" th:href="@{/toLogin}">
                        <i class="address card icon"></i> cancellation
                    </a>
                </div>
            </div>
        </div>
    </div>

    <div class="ui segment" style="text-align: center">
        <h3>Spring Security Study by Zhen</h3>
    </div>

    <div>
        <br>
        <div class="ui three column stackable grid">
            <!-- sec:authorize="hasRole('vip1')" -->
            <div class="column" sec:authorize="hasRole('vip1')">
                <div class="ui raised segment">
                    <div class="ui">
                        <div class="content">
                            <h5 class="content">Level 1</h5>
                            <hr>
                            <div><a th:href="@{/level1/1}"><i class="bullhorn icon"></i> Level-1-1</a></div>
                            <div><a th:href="@{/level1/2}"><i class="bullhorn icon"></i> Level-1-2</a></div>
                            <div><a th:href="@{/level1/3}"><i class="bullhorn icon"></i> Level-1-3</a></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="column" sec:authorize="hasRole('vip2')">
                <div class="ui raised segment">
                    <div class="ui">
                        <div class="content">
                            <h5 class="content">Level 2</h5>
                            <hr>
                            <div><a th:href="@{/level2/1}"><i class="bullhorn icon"></i> Level-2-1</a></div>
                            <div><a th:href="@{/level2/2}"><i class="bullhorn icon"></i> Level-2-2</a></div>
                            <div><a th:href="@{/level2/3}"><i class="bullhorn icon"></i> Level-2-3</a></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="column" sec:authorize="hasRole('vip3')">
                <div class="ui raised segment">
                    <div class="ui">
                        <div class="content">
                            <h5 class="content">Level 3</h5>
                            <hr>
                            <div><a th:href="@{/level3/1}"><i class="bullhorn icon"></i> Level-3-1</a></div>
                            <div><a th:href="@{/level3/2}"><i class="bullhorn icon"></i> Level-3-2</a></div>
                            <div><a th:href="@{/level3/3}"><i class="bullhorn icon"></i> Level-3-3</a></div>
                        </div>
                    </div>
                </div>
            </div>

        </div>
    </div>

</div>


<script th:src="@{/qinjiang/js/jquery-3.1.1.min.js}"></script>
<script th:src="@{/qinjiang/js/semantic.min.js}"></script>

</body>
</html>

Topics: Java Front-end Spring Boot Tomcat Back-end