What is Spring Security

Spring Security is a Security framework that provides declarative secure access control solutions for Spring-based enterprise applications.

Spring Security is a powerful and highly customizable authentication and access control framework focused on Java applications. It’s actually a standard for protecting Spring-based applications.

It provides a set of beans that can be configured in the context of Spring applications, taking full advantage of Spring IoC, DI, and AOP capabilities to provide declarative secure access control for applications, reducing the amount of repetitive coding required for enterprise system security control.

Spring Security website

2. Construction of experimental environment

1. Create a New SpringBoot project and import the web and Thymeleaf dependencies

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-java8time</artifactId>
        </dependency>
Copy the code

Disable automatic caching for Thymeleaf

spring.thymeleaf.cache=false
Copy the code

2. Import static resources

Static resource links

3. Write the Controller jump page to test the experimental environment

package com.cheng.conrtoller;

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

@Controller
public class RouterController {

    @RequestMapping({"/","index","index.html"})// All three requests can go to the home page
    public String toindex(a){
        return "index";
    }

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

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

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

    @RequestMapping("/level3/{id}")
    public String tolevel3(@PathVariable("id") int id){
        return "views/level3/"+id; }}Copy the code

Jump successfully, the experiment environment is OK!

3. User authentication and authorization

Import the spring-boot-starter- Security module and dependencies

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
           <groupId>org.thymeleaf.extras</groupId>
           <artifactId>thymeleaf-extras-springsecurity5</artifactId>
           <version>3.0.4. RELEASE</version>
        </dependency>
Copy the code

== Authentication and authorization ==

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 with a user name and password, sometimes in combination with authentication factors.

Authorization

Authorization occurs after the system successfully authenticates your identity and eventually grants you full access to resources such as information, files, databases, funds, locations, almost anything.

This concept is universal, and does not exist only in Spring Security.

Write configuration classes to implement authentication and authorization functions

package com.cheng.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;


// The configuration class crosscuts the implementation and does not affect the original code
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // Rules of authorization
        http.authorizeRequests().antMatchers("/").permitAll()// The home page is accessible to all
        // The VIP page can be accessed only by the corresponding role
        .antMatchers("/level1/**").hasRole("vip1")
        .antMatchers("/level2/**").hasRole("vip2")
        .antMatchers("/level3/**").hasRole("vip3");

        // The default login page is displayed when you have no access permission
        http.formLogin();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // Authentication rules
        JdbcAuthentication () jdbcAuthentication() jdbcAuthentication()
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())// Encrypt the password with the cipher encoder
                .withUser("cheng").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1"."vip2")
                .and()// Use "and" to connect users. These users are fake
                .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1"."vip2"."vip3")
                .and()
                .withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1"); }}Copy the code

Startup program test:

1. Visit the home page first, and everyone can access it

2. Visit the VIP page. Take viP2 as an example

3. At this time, we log in again for authentication. After successful login, the user has the corresponding permissions

So accessing the functional pages of VIP1 and VIP2 succeeds, but accessing the functional pages of VIP3 fails.

== Note: must give the user password code, otherwise the login will be reported error, unable to log in! = =

4. The test is complete. The user is authenticated and authorized successfully.

4. Logout function

The user logout function is enabled

 http.logout();
Copy the code

Point into the source code, see in addition to logout what function?

You can also remove the cookie, invalidate the session, and customize the logout page by accessing the /logout request.

                <! - cancellation - >
                <a class="item" th:href="@{/logout}">
                    <i class="sign-out icon"></i>The cancellation</a>
Copy the code
// Enable the logout function and return to the home page
http.logout().logoutSuccessUrl("/");
Copy the code

Test: start the program, first login a user, access a user rights page, and then click logout, successful return to the home page!

5. Permission control function

There is a problem with our above home page display, that is, after the user login, the home page is the function of all permissions, not according to the user’s permissions to show the user functions, such as cheng user, the permission is vip1, 2, cheng login we should only show the function of ViP1 and 2, should not show the function of Vip3; The same guest user has vip1, so we just show him what viP1 can do. Let’s implement this permission control function.

This is done in conjunction with Thymeleaf:

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity5</artifactId>
    <version>3.0.4. RELEASE</version>
</dependency>

Copy the code

Displays the logout and login buttons, and displays the user name and role name after login

<! -- Login logout -->
<div class="right menu">
    <! -- Not logged in, do not display the home page! IsAuthenticated () User not logged in -->
    <div sec:authorize=! "" isAuthenticated()">
        <a class="item" th:href="@{/toLogin}">
            <i class="address card icon"></i>The login</a>
    </div>
    
    <! -- If logged in, display the logout button and user name -->
    <div sec:authorize="isAuthenticated()">
        <a class="item">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="sign-out icon"></i>The cancellation</a>
    </div>
</div>
Copy the code

Start the program, test:

The first is the case of non-login, only login is displayed, not logout

Visit Login to request a login (this is springBoot’s built-in login page), which displays the user name, role name, and logout button

The page is displayed based on role rights

sec:authorize="hasRole('vip1')">

sec:authorize="hasRole('vip2')">

sec:authorize="hasRole('vip3')">

<div class="ui three column stackable grid">
    <div class="column">
        <div class="ui raised segment">
            <div class="ui">

                <div class="content" sec:authorize="hasRole('vip1')"><! -- If you have vip1 permissions, display the following interface -->
                    <h5 class="content">The function of the VIP1</h5>
                    <hr>
                    <div><a th:href="@{/level1/1}"><i class="bullhorn icon"></i>The login</a></div>
                    <div><a th:href="@{/level1/2}"><i class="bullhorn icon"></i>browse</a></div>
                    <div><a th:href="@{/level1/3}"><i class="bullhorn icon"></i>access</a></div>
                </div>
            </div>
        </div>
    </div>

    <div class="column">
        <div class="ui raised segment">
            <div class="ui">
                <div class="content" sec:authorize="hasRole('vip2')">
                    <h5 class="content">The function of the VIP2</h5>
                    <hr>
                    <div><a th:href="@{/level2/1}"><i class="bullhorn icon"></i>copy</a></div>
                    <div><a th:href="@{/level2/2}"><i class="bullhorn icon"></i>paste</a></div>
                    <div><a th:href="@{/level2/3}"><i class="bullhorn icon"></i>communication</a></div>
                </div>
            </div>
        </div>
    </div>

    <div class="column">
        <div class="ui raised segment">
            <div class="ui">
                <div class="content" sec:authorize="hasRole('vip3')">
                    <h5 class="content">The function of VIP3</h5>
                    <hr>
                    <div><a th:href="@{/level3/1}"><i class="bullhorn icon"></i>download</a></div>
                    <div><a th:href="@{/level3/2}"><i class="bullhorn icon"></i>upload</a></div>
                    <div><a th:href="@{/level3/3}"><i class="bullhorn icon"></i>Modify the</a></div>
                </div>
            </div>
        </div>
    </div>
</div>
Copy the code

To start the test, first without logging in:

Then log in to the Cheng user:

As you can see, the roles of cheng users are vip1 and vip2, so only the vip1 and Vip2 interfaces are displayed. Test successful!

6. Remember me and login page customization

Turn on the remember me function

// Enable the "remember me" function to save cookies. The default saving time is two weeks
http.rememberMe().rememberMeParameter("remember");// Customize the receiving front end parameters
Copy the code

Login page customization

// The default springBoot login page is displayed when you have no permission to access it
http.formLogin()// When you customize the login screen, the default login screen is overwritten
        .loginPage("/toLogin")// Login screen
        .usernameParameter("user")//usernameParameter("user").passwordParameter(" PWD ") Custom receiving parameter
        .passwordParameter("pwd")
        .loginProcessingUrl("/login");// Login access path: after submitting the form, jump to the address, can be regarded as a transfer station, this step is a process to verify the user
Copy the code

Add login page after remember me function;

<! DOCTYPEhtml>
<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>The login</title>
    <! --semantic-ui-->
    <link href="https://cdn.bootcss.com/semantic-ui/2.4.1/semantic.min.css" rel="stylesheet">
</head>
<body>

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

    <div class="ui segment">

        <div style="text-align: center">
            <h1 class="header">The login</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="@{/login}" method="post">
                            <div class="field">
                                <label>Username</label>
                                <div class="ui left icon input">
                                    <input type="text" placeholder="Username" name="user">
                                    <i class="user icon"></i>
                                </div>
                            </div>
                            <div class="field">
                                <label>Password</label>
                                <div class="ui left icon input">
                                    <input type="password" name="pwd">
                                    <i class="lock icon"></i>
                                </div>
                            </div>
                            <div class="field">
                                <input type="checkbox" name="remember">Remember that I</div>

                            <input type="submit" class="ui blue submit button"/>
                        </form>
                    </div>
                </div>
            </div>
        </div>


        <div style="text-align: center">
            <div class="ui label">
                </i>registered</div>
            <br><br>
            <small>https://blog.csdn.net/wpc2018?spm=1011.2124.3001.5343</small>
        </div>
        <div class="ui segment" style="text-align: center">
            <h3>Spring Security Study by A thousand miles</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>
Copy the code

7,

Two functions of the Security core: authentication and authorization

package com.cheng.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;
    
// Configuration class crosscutting
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    // Rules of authorization
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        
        http.authorizeRequests().antMatchers("/").permitAll()// The home page is accessible to all
        // The VIP page can be accessed only by the corresponding role
        .antMatchers("/level1/**").hasRole("vip1")
        .antMatchers("/level2/**").hasRole("vip2")
        .antMatchers("/level3/**").hasRole("vip3");

        // The default springBoot login page is displayed when you have no permission to access it
        http.formLogin()// When you customize the login screen, the default login screen is overwritten
                .loginPage("/toLogin")// Login screen
                .usernameParameter("user")//usernameParameter("user").passwordParameter(" PWD ") Custom receiving parameter
                .passwordParameter("pwd")
                .loginProcessingUrl("/login");// Login access path: after submitting the form, jump to the address, can be regarded as a transfer station, this step is a process to verify the user

        // Enable the logout function and return to the home page
        http.logout().logoutSuccessUrl("/");

        http.csrf().disable();// Disable CSRF protection, which is enabled by default

        // Enable the Remember me function
        http.rememberMe().rememberMeParameter("remember");// Customize the receiving front end parameters
    }


    // Authentication rules
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {     
        JdbcAuthentication () jdbcAuthentication() jdbcAuthentication()
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())// Encrypt the password with the cipher encoder
                .withUser("cheng").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1"."vip2")
                .and()// Use "and" to connect users. These users are fake
                .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1"."vip2"."vip3")
                .and()
                .withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1"); }}Copy the code