2024.5.16 Thursday
Content
14. Building SpringSecurity Environment
14.1. Introduction to Security
14.1.1. In web development, security has always been a very important aspect. Although security is a non-functional requirement of the application, it should be considered from the beginning of application development. If security issues are only considered in the later stages of application development, it may lead to a dilemma: on the one hand, the application has serious security vulnerabilities, cannot meet user requirements, and may result in attackers stealing user’s private data; on the other hand, the basic architecture of the application has been determined, fixing security vulnerabilities may require significant architectural adjustments, thus requiring more development time, affecting the application’s release process. Therefore, security-related factors should be considered from the first day of application development and throughout the entire development process.
14.1.2. There are well-known frameworks on the market: Shiro, Spring Security!
14.1.3. Here it needs to be explained that the emergence of each framework is to solve a certain problem, so what problem does the Spring Security framework solve?
14.1.4. Official website (https://spring.io/projects/spring-security):
(Chinese version: https://springdoc.cn/spring-security/)
14.1.4.1. Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications.
14.1.4.2. Spring Security is a framework that focuses on providing both authentication and authorization to Java applications. Like all Spring projects, the real power of Spring Security is found in how easily it can be extended to meet custom requirements.
14.1.5. Spring Security is a powerful and highly customizable authentication and access control framework. It is the de-facto standard for securing Spring-based applications.
14.1.6. Spring Security is a framework that focuses on providing both authentication and authorization to Java applications. Like all Spring projects, the real power of Spring Security is found in how easily it can be extended to meet custom requirements.
14.1.7. From the introduction on the official website, it can be known that this is an authorization framework. How did we control permissions when we didn’t use a framework in previous projects? Permissions are generally subdivided into functional permissions, access permissions, and menu permissions. The code would be written very cumbersome and redundant.
14.1.8. How to solve the problem of cumbersome and redundant permission code written before? Some mainstream frameworks have emerged, and Spring Security is one of them.
14.1.9. Spring is a very popular and successful Java application development framework. Based on the Spring framework, Spring Security provides a complete solution for web application security. Generally speaking, the security of web applications includes two parts: user authentication and user 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 the user to provide a username and password. The system completes the authentication process by verifying the username and password. User authorization refers to verifying whether a user has permission to perform a certain operation. In a system, different users have different permissions. For example, for a file, some users can only read it, while others can modify it. Generally speaking, the system will assign different roles to different users, and each role corresponds to a series of permissions.
14.1.10. For the two application scenarios mentioned above, Spring Security framework has good support. 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, etc. In terms of user authorization, Spring Security provides role-based access control and access control lists (ACLs), which can control domain objects in the application in a fine-grained manner.
14.2. Testing
14.2.1. Create a new project named springboot-06-security
Add Maven support (click the plus sign in Project Structure->Modules to add the corresponding project), as usual, modify Maven, JDK, and Java versions in settings, JDK, and Java versions in Project Structure. Modify the Springframework version to 2.7.13 in pom.xml, add Thymeleaf dependency in pom.xml, and reload Maven.
<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
Delete redundant files.
14.2.2. Import Resources
Resources have been uploaded to: https://download.csdn.net/download/2401_83329143/89316854
14.2.3. Create a new controller folder
14.2.3.1. Create a new file named RouterController.java
package com.P34.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({"/", "/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;
}
}
14.2.3.2. Modify application.properties to disable cache
spring.application.name=springboot-06-security
spring.thymeleaf.cache=false
14.2.3.3. Run Springboot06SecurityApplication.java
Access http://localhost:8080/
14.3. Understanding Spring Security
Spring Security is a security framework for Spring projects and the default technology choice for the underlying security module of Spring Boot. It enables powerful web security controls with minimal configuration by simply importing the spring-boot-starter-security
module.
Remember a few key classes:
WebSecurityConfigurerAdapter
: Customizes Security strategies.AuthenticationManagerBuilder
: Customizes authentication strategies.@EnableWebSecurity
: Enables WebSecurity mode.
The two main goals of Spring Security are “Authentication” and “Authorization” (Access Control).
14.3.1. Authentication
Authentication is about verifying your credentials, such as username/userID and password, to validate your identity. Authentication is typically done with a username and password, sometimes combined with authentication factors.
14.3.2. Authorization
Authorization occurs after the system successfully verifies your identity, ultimately granting you full access to resources (such as information, files, databases, funds, locations, almost anything). This concept is universal, not only present in Spring Security.
14.4. Authentication and Authorization
Currently, our test environment is accessible to any user. Let’s use Spring Security to add authentication and authorization functionality.
14.4.1. Import Spring Security module (pom.xml)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.13</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>springboot-06-security</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-06-security</name>
<description>springboot-06-security</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
14.4.2. Create a new config folder
Create SecurityConfig.java
package com.P34.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;
// Implement interceptor functionality using AOP
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// Override methods using alt+insert
// Method chaining
@Override
protected void configure(HttpSecurity http) throws Exception {
// Everyone can access the home page, functional pages are only open to authorized users
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
}
// public WebSecurityCustomizer webSecurityCustomizer() - New method
}
14.4.3. Restart
14.4.4. Modifying SecurityConfig.java
Adding a statement to redirect to the login page if unauthorized
package com.P34.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;
// Implement interceptor functionality using AOP
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//alt+insert->override methods
//Method chaining
@Override
protected void configure(HttpSecurity http) throws Exception {
// Everyone can access the home page, functional pages are only open to authorized users
// Request authorization rules
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
// Redirect to login page if not authorized
http.formLogin();
}
// public WebSecurityCustomizer webSecurityCustomizer() - New method
}
After restarting, try accessing http://localhost:8080/level1/1 again without permission. Unlike the previous step, this time it doesn’t display error 403; instead, it directly redirects to the login page.
14.4.5. Continuing Modification in SecurityConfig.java
package com.P34.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;
// Implement interceptor functionality using AOP
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//alt+insert->override methods
//Method chaining
//Authorization
@Override
protected void configure(HttpSecurity http) throws Exception {
// Everyone can access the home page, functional pages are only open to authorized users
// Request authorization rules
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
// Redirect to login page if not authorized, can check source code of formLogin for more details
http.formLogin();
}
// public WebSecurityCustomizer webSecurityCustomizer() - New method
//Authentication
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// Syntax example visible by opening WebSecurityConfigurerAdapter at line 194:
/**
* protected void configure(AuthenticationManagerBuilder auth) {
* auth
* // enable in memory based authentication with a user named
* // "user" and "admin"
* .inMemoryAuthentication().withUser("user").password("password").roles("USER").and()
* .withUser("admin").password("password").roles("USER", "ADMIN");
* }
*/
// These data should theoretically be retrieved from the database
// Running it shows "There was an unexpected error (type=Internal Server Error, status=500)".
// The password encoding is missing (There is no PasswordEncoder mapped for the id “null”), so we need to encrypt the "password" in the code
// Many encryption methods have been added in Spring Security 5.0+: click BCryptPasswordEncoder->PasswordEncoder->click the green "I" on the left sidebar (see image below)
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("Zzz").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2")
.and()
.withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
.and()
.withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip3");
}
}
14.4.6. Restart
Login and verify the permissions for the three users created.
14.4.6.1. Zzz
Both Level1 and Level2 are accessible.
Level3 is not accessible.
14.4.6.2. Root
Levels 1, 2, and 3 are accessible. The pages are similar to those accessible to Zzz and hence not shown.
14.4.6.3. Guest
Only Level3 is accessible.
Access is denied for Levels 1, 2, and for pages accessible to Zzz, hence not shown.