Spring Boot learning notes - Spring Security

Spring Boot learning

Official website: https://spring.io/projects/spring-boot#overview

file: https://docs.spring.io/spring-boot/docs/2.2.6.RELEASE/reference/html/

Reference video: [crazy God says Java] the latest tutorial of SpringBoot, IDEA version, is easy to understand_ Beep beep beep_ bilibili

Project complete reference code: lexiaoyuan/SpringBootStudy: My Spring Boot study notes (github.com),Springboot study: my Spring Boot study notes (gitee.com)

Spring Security

Official website: https://spring.io/projects/spring-security

file: https://docs.spring.io/spring-security/site/docs/5.3.2.BUILD-SNAPSHOT/reference/html5/

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

Remember several classes:

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

Test environment construction

  • Create a controller package, and create a routercontroller under the controller package Java, used to jump to various pages
@Controller
public class RouterController {
    @GetMapping({"/", "/index"})
    public String index(){
        return "index";
    }

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

    @GetMapping("/level1/{id}")
    public String level1(@PathVariable("id") int id) {
        return "views/level1/"+id;
    }

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

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

}
  • Run the project to access: http://localhost:8080/ , test whether the page Jump is normal, normal!

Certification and authorization

  • Introduce the Spring Security module in POM Adding dependencies to XML
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
  • Write a configuration class, create a new config directory, and create a new securityconfig java

    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        // to grant authorization
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // Request authorization rule
            http.authorizeRequests()
                    .antMatchers("/").permitAll()   // The home page is accessible to everyone
                    .antMatchers("/level1/**").hasRole("vip1")
                    .antMatchers("/level2/**").hasRole("vip2")
                    .antMatchers("/level3/**").hasRole("vip3");
    
            // Open the login page. If you don't have permission, it defaults to the login page / login
            http.formLogin();
        }
    
        // authentication
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    
             // Get the user and corresponding role from memory. This data should be read from the database
            //Spring security 5.0 adds a variety of encryption methods and changes the password format.
            //If we want our project to log in normally, we need to modify the code in configure. We need to encrypt the password transmitted from the front end in some way
            //BCrypt encryption is officially recommended by spring security.
            auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                    .withUser("lexiaoyuan").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1", "vip2")
                    .and()
                    .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1", "vip2", "vip3")
                    .and()
                    .withUser("beta").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");
        }
    }
    
  • Run the project to access: http://localhost:8080/ , want to enter level 1 (or 2 or 3). Or direct access to: http://localhost:8080/login , it will automatically jump to a login page (provided by the frame).

  • If you enter the wrong user name and password (except for the three users defined above: lexiaoyuan, root, beta and the corresponding password), you will jump to http://localhost:8080/login?error

  • Enter level yuan, 123456, log in, and click the link in level. It is found that you can only access level 1 and level 2. An error will be reported when accessing Level 3.


  • Similarly, you can only access the corresponding page after entering other set users. Test successful!

Logout and permission control

  • Enable logoff function
// to grant authorization
@Override
protected void configure(HttpSecurity http) throws Exception {
    // Request authorization rule
    http.authorizeRequests()
        .antMatchers("/").permitAll()   // The home page is accessible to everyone
        .antMatchers("/level1/**").hasRole("vip1")
        .antMatchers("/level2/**").hasRole("vip2")
        .antMatchers("/level3/**").hasRole("vip3");

    // Open the login page. If you don't have permission, it defaults to the login page / login
    http.formLogin();

    // Enable logoff function
    http.logout();
}
  • Front end index Add a logout button in HTML, and the request is / logout (the default request address in the source code)
<!--Login and logout-->
<div class="right menu">
    <!--Not logged in-->
    <a class="item" th:href="@{/toLogin}">
        <i class="address card icon"></i> Sign in
    </a>
    <a class="item" th:href="@{/logout}">
        <i class="sign-out icon"></i> cancellation
    </a>
</div>
  • Test it. Run the project to access: http://localhost:8080/login

After logging in, click log out


Click the Log Out button

Jump back to the login page

  • After logging off successfully, jump to the home page
@Override
protected void configure(HttpSecurity http) throws Exception {
    // ...
    // Log off successfully and jump to the home page
    http.logout().logoutSuccessUrl("/");
}
  • Test it, rerun the project, and visit: http://localhost:8080/login , after successful login, click the logout button and jump to the home page. success!

Modify the navigation bar according to the authentication status

When the user does not log in, only the login button is displayed on the navigation bar. After the user logs in, the navigation bar can display the login user information and logout button.

You need to combine some methods provided by Thymeleaf + Spring Security.

Official documents: https://www.thymeleaf.org/doc/articles/springsecurity.html

GitHub address: https://github.com/thymeleaf/thymeleaf-extras-springsecurity

Official examples: https://github.com/thymeleaf/thymeleafexamples-springsecurity

  • First, in POM Introducing new dependencies into XML
<!-- 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 index HTML, add namespace
xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
  • Modify index HTML, determine whether to log in through sec:authorize="isAuthenticated()
<!--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>

    <!--Logged in-->
    <div sec:authorize="isAuthenticated()">
        <a class="item">
            user name:<span sec:authentication="name"></span>
            Role:<span sec:authentication="principal.authorities"></span>
        </a>
        <a class="item" th:href="@{/logout}">
            <i class="sign-out icon"></i> cancellation
        </a>
    </div>
</div>
  • Rerun the project to access: http://localhost:8080/ , you can see that only the login button is displayed

  • visit: http://localhost:8080/login After logging in successfully, you can see that the logged in user and his / her roles are displayed

  • Click logout again, confirm logout, and return to the home page.


  • OK, this requirement is completed!

Different pages are displayed according to different roles of users

  • Continue to modify index HTML, use sec:authorize="hasRole('vip1 ')" to complete role function authentication
<!--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>

<!--sec:authorize="hasRole('vip2')"-->
<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>

<!--sec:authorize="hasRole('vip3')"-->
<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>
  • Re Build the project. Test: Visit: http://localhost:8080/ , you can see that you haven't logged in yet, and none of them are displayed

Note: if the access is not updated after re building, the thymeleaf template may be cached, which can be found in application Properties, and then re run the project

spring.thymeleaf.cache=false

  • visit: http://localhost:8080/login After successful login, you can see the page that the corresponding user is allowed to display.

  • ok, logout and permission control are complete!

Remember me

  • Open remember me
@Override
protected void configure(HttpSecurity http) throws Exception {
    // ...
    // Open and remember me
    http.rememberMe();
}
  • visit: http://localhost:8080/login , there will be one more button to remember me, enter the user name and password, and check remember me to log in

  • Press F12 to view the browser's cookie. You can see that after successful login, the cookie will be sent to the browser for saving

  • Close the browser and visit again http://localhost:8080/ , the home page will be displayed directly without login

  • After clicking log off and confirm, you can see that the cookie has been deleted

Custom home page

Now this Login page is the default of spring security. How can we use the Login interface written by ourselves?

  • Open custom login page
// Custom home page: loginPage("/toLogin")
http.formLogin().loginPage("/toLogin");
  • Point to our custom request at the front end
<a class="item" th:href="@{/toLogin}">
    <i class="address card icon"></i> Sign in
</a>
  • Test: access: http://localhost:8080/ , click the login button to jump to the login page written by yourself

  • After entering the user name and password and clicking the login button, an error will be reported because we have not written the request to accept login

  • Accept login request: [method 1]: modify login HTML, which is submitted to the / toLogin request by post
<form th:action="@{/toLogin}" 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"/>
</form>

Note: the input name attribute of user name and password in the submitted form must be username and password (this is the default accepted name and needs to be matched), otherwise it will jump to http://localhost:8080/toLogin?error , the page is still on the login page.

  • To rebuild the project, visit: http://localhost:8080/toLogin After entering the user name and password, you can see that you log in normally.

  • Accept login request: [method 2]: continue setting after the customized home page
// Custom home page: loginPage("/toLogin")
// Request to log in to submit form: loginProcessingUrl("/login")
http.formLogin()
        .loginPage("/toLogin")
        .usernameParameter("username")
        .passwordParameter("password")
        .loginProcessingUrl("/login");
  • Then modify login HTML, go / login request
<form th:action="@{/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"/>
</form>
  • After rerunning the project, access: http://localhost:8080/toLogin After entering the user name and password, you can see it or log in normally.

  • In the custom page implementation, remember my function in login Add a multi selection box to remember me in HTML
<div class="field">
    <input type="checkbox" name="remember">Remember me
</div>

Note: if the value of the name attribute is "remember me", it can be omitted rememberMeParameter("remember")

  • Continue to configure after opening the remember me method rememberMeParameter("remember")
// Set the name of my input to submit rememberMeParameter("remember"), the default is remember me
http.rememberMe().rememberMeParameter("remember");
  • Rerun the project to access: http://localhost:8080/toLogin , you can see that there is an additional selection box to remember me. After entering the user name and password, check remember me and log in. You can see that you have successfully logged in.


  • Close the browser and visit: http://localhost:8080/ , you can see that the logged in page will be displayed directly. You don't have to log in again.
  • OK, customize the home page!

Complete code of configuration class attached

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    // to grant authorization
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // Request authorization rule
        http.authorizeRequests()
                .antMatchers("/").permitAll()   // The home page is accessible to everyone
                .antMatchers("/level1/**").hasRole("vip1")
                .antMatchers("/level2/**").hasRole("vip2")
                .antMatchers("/level3/**").hasRole("vip3");

        // Open the login page. If you don't have permission, it defaults to the login page / login
        // Custom home page: loginPage("/toLogin")
        // Request to log in to submit form: loginProcessingUrl("/login")
        http.formLogin()
                .loginPage("/toLogin")
                .usernameParameter("username")
                .passwordParameter("password")
                .loginProcessingUrl("/login");

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

        // After using the custom login page, you need to turn off the csrf function: Cross Site Request Forgery. By default, logout requests can only be submitted through post
        //http.csrf().disable();

        // Open and remember me
        // Set the name of my input to submit rememberMeParameter("remember"), the default is remember me
        http.rememberMe().rememberMeParameter("remember");
    }

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

        // Get the user and corresponding role from memory. This data should be read from the database
        //Spring security 5.0 adds a variety of encryption methods and changes the password format.
        //If we want our project to log in normally, we need to modify the code in configure. We need to encrypt the password transmitted from the front end in some way
        //BCrypt encryption is officially recommended by spring security.
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("lexiaoyuan").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1", "vip2")
                .and()
                .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1", "vip2", "vip3")
                .and()
                .withUser("beta").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");
    }
}

Keywords: Java Spring Boot Spring Security

Added by xinnex on Tue, 25 Jan 2022 23:15:22 +0200