SpringSecurity (safety)

Safety profile

Security has always been a very important aspect of Web development. Security, while a non-functional requirement of an application, should be considered early in application development. If security is considered at the late stage of application development, you may be caught in a dilemma: on the one hand, the application has serious security vulnerabilities, which cannot meet users’ requirements and may cause users’ private data to be stolen by attackers; On the other hand, the basic architecture of the application has been determined. In order to fix security vulnerabilities, it may be necessary to make major adjustments to the system architecture, which requires more development time and affects the application release process. Therefore, security considerations should be taken into account from the first day of application development and throughout the entire application development process.

There are some famous ones in the market: Shiro, Spring Security!

Each framework is designed to solve a problem. What problem is the Spring Security framework designed to solve?


IO /projects/sp…


Spring Security is a powerful and highly customizable authentication and access control framework. It is essentially a standard for securing Spring-based applications.

Spring Security is a framework that focuses on providing authentication and authorization for Java applications. As with all Spring projects, the real power of Spring security is that it can be easily extended to meet custom requirements

From the introduction of the official website we know that this is a permission framework. How did we control the permissions when we did the project without using the framework? Permissions are generally subdivided into function permissions, access permissions, and menu permissions. The code will be very cumbersome and redundant.

Spring Scecurity is one of the mainstream frameworks that have emerged to solve the problem of writing permission codes that are cumbersome and redundant.

Spring is a very popular and successful Java application development framework. Spring Security provides a complete solution for Web application Security based on the Spring framework. Generally speaking, the security of Web applications includes Authentication and Authorization. User authentication refers to verifying whether a user is a legitimate subject in the system, that is, whether the user can access the system. User authentication generally requires a user name and password. The system verifies the user name and password to complete the authentication process. User authorization refers to verifying whether a user has permission to perform an operation. In a system, different users have different permissions. For example, some users can only read a file, while others can modify it. Generally speaking, the system assigns different roles to different users, and each role has a series of permissions.

The Spring Security framework has good support for both of the application scenarios mentioned above. In terms of user authentication, the Spring Security framework supports mainstream authentication methods, including HTTP basic authentication, HTTP form authentication, HTTP digest authentication, OpenID and LDAP. On the user authorization side, Spring Security provides role-based Access Control and Access Control Lists (ACLs) for fine-grained Control of domain objects in applications.


Think about:

When developing a Web site: When should security be considered? At the beginning of design, of course!

  • 1. Vulnerability and privacy disclosure
  • 2. Once the architecture is determined, it is difficult to modify it later

Is Shiro different from Spring Security? Highly similar, except for the name and the class

  • certification
  • Authorization (VIP1, VIP2, VIP3)

What permissions does it have?

  • Give you permission
  • Access permissions
  • Menu permissions
  • .

We’ve used it before: interceptors, filters: lots of native code



Practical test

Experimental environment construction

VX public account: Light Breeze,

Static resource acquisition: SpringSecurity


1. Create a Springboot-07-Security project

An initial Springboot-Security project Web module, thymeleaf module

2. Import static resources

3. Shut down the template engine

Create the application.yml control template engine

spring:
  thymeleaf:
    cache: false
Copy the code

4, controller control jump!


@Controller
public class RouterController {

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

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

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

    @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; }}Copy the code

5, test whether the experimental environment is OK!



Know SpringSecurity

Spring Security is a Security framework for Spring projects and the default technology selection for Spring Boot Security module. It can realize powerful Web Security control. We only need to introduce the spring-boot-starter-Security module, do a little configuration, can achieve powerful security management!

Keep a few classes in mind:

  • WebSecurityConfigurerAdapter: custom Security strategy

  • AuthenticationManagerBuilder: custom authentication strategy

  • @enableWebSecurity: Enable the WebSecurity mode

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

Authentication

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

Authentication is usually done with a username and password, sometimes in combination with an authentication factor.

Authorization

Authorization occurs when the system successfully verifies your identity, eventually granting you full access to resources such as information, files, databases, funds, locations, and just about anything.

This concept is universal, not unique to Spring Security.


Authentication and Authorization

Currently, our test environment is accessible to anyone, and we use Spring Security to add authentication and authorization capabilities

1. Introduce the Spring Security module

    <! -... other dependency elements ... -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
Copy the code

2. Write Spring Security configuration classes

IO /projects/sp…

Look at the version in our own project and find the corresponding help documentation: docs.spring. IO /spring-secu…

3. Write basic configuration classes

package com.cy.config;

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;

@EnableWebSecurity // Enable WebSecurity mode
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception{}}Copy the code

4. Customize authorization rules for requests

package com.cy.config;

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;

@EnableWebSecurity // Enable WebSecurity mode
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // The first page is accessible to all, the function page is only accessible to those with proper permissions
        // http.authorizerequests () authentication requests
        http.authorizeRequests().antMatchers("/").permitAll()
                .antMatchers("/level1/**").hasRole("vip1")
                .antMatchers("/level2/**").hasRole("vip2")
                .antMatchers("/level3/**").hasRole("vip3"); }}Copy the code

5, test,

We can find in addition to the home page can not go! Because we currently do not have a role to log in, because the request requires the role to log in to have the corresponding permissions!

6. Enable auto-configured login!

Add the following configuration to the configure() method to enable auto-configured login!

        // Enable the automatic login function
        // /login request comes to the login page
        // /login? Error redirects to this to indicate a login failure
        http.formLogin();
Copy the code

7, test,

Found that when there is no permission, will jump to the login page!8. View the comment information of the login page.

We can define the certification rules and rewrite the configure (AuthenticationManagerBuilder auth) method

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

        // Define it in memory or in JDBC at....
        auth.inMemoryAuthentication()
                .withUser("qingfeng").password("123456").roles("vip2"."vip3")
                .and()
                .withUser("admin").password("123456").roles("vip1"."vip2"."vip3")
                .and()
                .withUser("root").password("123456").roles("vip1"."vip2");
    }
Copy the code

9, test, we can use these accounts to log in to test! An error will be reported if found!

There is no PasswordEncoder mapped for the ID “null”

10. The reason is that we need to encrypt the password passed from the front end in some way, otherwise we can’t log in and modify the code

Spring 2.1.x can be used directly
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        // Define it in memory or in JDBC at....
        //Spring Security 5.0 has added multiple encryption methods and changed the password format.
        // We need to modify the configure code in order for our project to log in properly. We're going to have to somehow encrypt the password that comes from the front end
        // Spring Security officially recommends using bcrypt.

        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("qingfeng").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2"."vip3")
                .and()
                .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1"."vip2"."vip3")
                .and()
                .withUser("admin").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1"."vip2"); }}Copy the code

11. Test, find, login is successful, and each role can only access the rules under its own authentication! done



Permission control and logout

1. Enable the logout function for automatic configuration

// Customize authorization rules for requests
@Override
protected void configure(HttpSecurity http) throws Exception {
   //....
   // Enable the automatic configuration logout function
      // / Logout The request is logged out
   http.logout();
}
Copy the code
        // Log out. The log out function is enabled to clear cookies and sessions
        http.logout().deleteCookies("remove").invalidateHttpSession(true);
Copy the code

2. Add the logout button

We added a logout button to the front of the index.html navigation bar

<! -- Logout --> <aclass="item" th:href="@{/logout}">
          <i class="sign-out icon"> < / I > login < / a >Copy the code

3, test,

We can go to test, after successful login click logout, found that the logout will jump to the login page!

4, logout jump home page

However, we want him to log out successfully, can still jump to the home page, how to deal with?

        http.logout().logoutSuccessUrl("/");
Copy the code

5, test,

After logging out, it is found to jump to the home page OK

6. Now we have another demand:

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 the logout button! There is also, for example, qingfeng user, it only has vip2, vip3 functions, so login will only show these two functions, and vip1 function menu does not show! This is the real site situation! How do you do that?

We need to combine some of the functionality in ThymeleafCopy the code

SEC: authorize=”isAuthenticated()”: Whether to authenticate login! To display different pages

Maven depends on:

<! -- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity4 -->
<dependency>
   <groupId>org.thymeleaf.extras</groupId>
   <artifactId>thymeleaf-extras-springsecurity5</artifactId>
   <version>3.04..RELEASE</version>
</dependency>
Copy the code

7. Modify our front-end page

Import namespace

xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"
Copy the code

Modified the navigation bar to add authentication judgment

<! -- Log out --> <divclass="right menu"> <! -- If not logged in --> <! -- Determine whether the user logs in SEC :authorize=! "" isAuthenticated()"-->
                <div sec:authorize=! "" isAuthenticated()">
                    <a class="item" th:href="@{/login}">
                        <i class="address card icon"></ I > Login </a> </div> <! --> <div SEC :authorize="isAuthenticated()">
                    <a class="item">
                        <i class="address card icon"></ I > User name: <span SEC :authentication="principal.username"></span>&nbsp; &nbsp; Role: <span SEC :authentication="principal.authorities"></span> </a> <! -- Logout --> <aclass="item" th:href="@{/logout}">
                    <i class="sign-out icon"</div> </div>Copy the code

8. Restart the test

We can log in and try it, and when we log in, yes, it shows the page we want;

9. 404 Solution

If a 404 is logged out, because it prevents CSRF cross-site request forgery by default, we can either change the request to POST form submission or turn it off in Spring Security because of security issuescsrfFunction; Let’s try: add in configurationhttp.csrf().disable();

http.csrf().disable();// Disable CSRF: Cross-site request forgery. By default, only post can be used to submit the logout request
http.logout().logoutSuccessUrl("/");
Copy the code

10. Role function block authentication

We continue to complete the following character feature block authentication!

    <div>
        <br>
        <div class="ui three column stackable grid">
            <! -- Menu according to user's role, dynamic implementation -->
            <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>
            <! -- Menu according to user's role, dynamic implementation -->
            <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>
            <! -- Menu according to user's role, dynamic implementation -->
            <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>
Copy the code

11, test,

Authority control and logout done!



Remember me function

Now, as long as we log in, close the browser, and log in again, it will let us log in again, but a lot of websites, is a function to remember the password, how to achieve this? Very simple

1. Enable the Remember me function

// Customize authorization rules for requests
@Override
protected void configure(HttpSecurity http) throws Exception {
/ /...
   // Remember my function, essentially cookies
   http.rememberMe();
}
Copy the code

2. Restart the test

We started the project again to test, and found that there was a “remember me” function on the login page. After logging in, we closed the browser, and then opened the browser again to access, and found that the user still existed!

Consider: How? It’s very simple

We can look in the browsercookieBy default, 14 error days are reported

3. Click Logout

When we hit Logout, we see,spring securityIt automatically deleted this for uscookie

4. Conclusions:

After successful login, the cookie will be sent to the browser to save, later login with this cookie, as long as the check can be passed without login. If you click Logout, the cookie is deleted!



Customizing login page

Now that the Login page is spring Security’s default, how can we use our own Login interface?

1. Specify loginPage

Specify loginpage after the previous loginpage configuration

@Override
    protected void configure(HttpSecurity http) throws Exception {
         / /...
        //loginPage: The page is displayed
        http.formLogin().loginPage("/toLogin");
Copy the code

2. Define the login request

Then the front end also needs to point to our own defined login request

<a class="item" th:href="@{/toLogin}">
   <i class="address card icon"></i>The login</a>
Copy the code

3. Configure the request submission mode

We need to login, we need to send this information to where, we also need to configure login.html to submit the request and the method, the method must be post:

A comment in the loginPage() source code says:

<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>
Copy the code

4. Configure the receive login

This request is submitted, and we need to validate it. How do we do that?

We can look at the source of the formLogin() method! We configure the parameters for the user name and password to receive the login!

        http.formLogin()
                .loginPage("/toLogin")
                .usernameParameter("username")
                .passwordParameter("password")
                .loginProcessingUrl("/login"); // Login form submission request;
Copy the code

5. Add more boxes to remember me

Add multiple checkboxes to remember me on the login page

<div class="field">
    <input type="checkbox" name="remember">Remember that I</div>
Copy the code

6. Back-end validation processing!

// Remember my parameters!
// Enable the remember me function, cookie, default save 2 weeks, custom receive front-end parameters
http.rememberMe().rememberMeParameter("remember");
Copy the code

7, test,


Complete configuration code

package com.cy.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 // Enable WebSecurity mode
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // The first page is accessible to all, the function page is only accessible to those with proper permissions
        // http.authorizerequests () authentication requests
        http.authorizeRequests().antMatchers("/").permitAll()
                .antMatchers("/level1/**").hasRole("vip1")
                .antMatchers("/level2/**").hasRole("vip2")
                .antMatchers("/level3/**").hasRole("vip3");

        // Enable the automatic login function
        // /login request comes to the login page
        // /login? Error redirects to this to indicate a login failure
        //loginPage: The page is displayed
        http.formLogin()
                .loginPage("/toLogin")
                .usernameParameter("username")
                .passwordParameter("password")
                .loginProcessingUrl("/login"); // Login form submission request;

        // Prevent web tools: get, post
        http.csrf().disable(); // Disable the CSRF function. The login failure must be caused by ~
        // Log out. The log out function is enabled
        http.logout().logoutSuccessUrl("/");
        http.rememberMe().rememberMeParameter("remember");
    }

    Spring 2.1.x can be used directly
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        // Define it in memory or in JDBC at....
        //Spring Security 5.0 has added multiple encryption methods and changed the password format.
        // We need to modify the configure code in order for our project to log in properly. We're going to have to somehow encrypt the password that comes from the front end
        // Spring Security officially recommends using bcrypt.
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("qingfeng").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2"."vip3")
                .and()
                .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1"."vip2"."vip3")
                .and()
                .withUser("admin").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1"."vip2"); }}Copy the code