Spring Security Based System Permission Management Tutorial
This article provides a comprehensive step‑by‑step guide on building a permission management system with Spring Security, covering database design, entity classes, Maven configuration, security configuration, dynamic menu loading, front‑end rendering using Thymeleaf, and complete testing with sample code and screenshots.
System Permission Management
In real‑world development, permission management is essential; this guide demonstrates a complete solution based on Spring Security, which offers high security and password encryption.
Technology Stack
The project uses Spring Boot, Spring Security, Spring Data JPA, Thymeleaf for templating, Bootstrap for UI, and MySQL as the database.
Database Design
Four tables are defined:
Menu ( TbMenu ) – stores all menus displayed on the page.
Role ( SysRole ) – stores roles and the menus they can access.
User ( SysUser ) – stores user credentials.
User‑Role mapping ( sys_user_role ) – many‑to‑many relationship generated by Spring Data JPA.
Project Setup
Create a Spring Boot project and add the following Maven dependencies (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.2.2.RELEASE</version>
</parent>
<groupId>com.mcy</groupId>
<artifactId>springboot-security</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- other dependencies omitted for brevity -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>Entity Classes
Menu entity ( TbMenu ) with parent‑child relationship:
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.mcy.springbootsecurity.custom.BaseEntity;
import org.springframework.data.annotation.CreatedBy;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
public class TbMenu extends BaseEntity
{
private String name;
private String url;
private Integer idx;
@JsonIgnore
private TbMenu parent;
@JsonIgnore
private List
children = new ArrayList<>();
// getters, setters, constructors omitted for brevity
}Role entity ( SysRole ) stores role name, code and hierarchical permissions:
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.mcy.springbootsecurity.custom.BaseEntity;
import org.springframework.data.annotation.CreatedBy;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
public class SysRole extends BaseEntity
{
private String name;
private String code;
@JsonIgnore
private SysRole parent;
private Integer idx;
@JsonIgnore
private List
children = new ArrayList<>();
// getters, setters, constructors omitted for brevity
}User entity ( SysUser ) with many‑to‑many relationship to roles:
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.mcy.springbootsecurity.custom.BaseEntity;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
public class SysUser extends BaseEntity
{
private String username;
private String password;
private String name;
private String address;
@JsonIgnore
private List
roles = new ArrayList<>();
// getters, setters, transient fields for role names/codes omitted for brevity
}Security Configuration
Configure authentication and authorization in WebSecurityConfig :
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private SysUserService userService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("aaa").password("{noop}1234").roles("DIY");
auth.userDetailsService(userService).passwordEncoder(new BCryptPasswordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.formLogin()
.loginPage("/login").permitAll()
.successForwardUrl("/main")
.failureUrl("/login?error");
http.authorizeRequests().antMatchers("/static/**", "/assets/**", "/webjars/**").permitAll();
http.logout().logoutUrl("/logout").permitAll();
http.authorizeRequests().anyRequest().authenticated();
}
}Utility Class
UserUtils obtains the currently logged‑in user and checks role membership:
@Component
public class UserUtils {
@Autowired
private SysUserService userService;
public SysUser getUser() {
String username = SecurityContextHolder.getContext().getAuthentication().getName();
return userService.findByUsername(username);
}
public Boolean hasRole(String roleName) {
UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
List
roleCodes = new ArrayList<>();
for (GrantedAuthority authority : userDetails.getAuthorities()) {
roleCodes.add(authority.getAuthority());
}
return roleCodes.contains(roleName);
}
}Dynamic Permission Menu Loading
Implement loadUserByUsername to build UserDetails with authorities derived from roles and their child permissions, then filter menus based on those authorities in TbMenuService.findAuditMenu and auditMenu methods.
Front‑End Menu Rendering
Use Thymeleaf together with LayUI to iterate over the menu list and render collapsible panels. Example snippet:
<div th:each="menu, menuStat : ${menus}" th:if="${menu.children.size() != 0}" class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<p data-toggle="collapse" data-parent="#accordion" th:href="|#collapseOne${menuStat.index}|">
<span th:text="${menu.name}">系统设置</span><span class="caret"></span>
</p>
</h4>
</div>
<div th:id="|collapseOne${menuStat.index}|" class="panel-collapse collapse">
<div class="panel-body">
<p th:each="subMenu : ${menu.children}" th:src="${subMenu.url}" th:text="${subMenu.name}">菜单管理</p>
</div>
</div>
</div>Testing and Results
Sample users (admin1, admin2, admin3) demonstrate different role‑based menu displays. Screenshots show menu trees for administrators, regular users, and test users, confirming that the permission filtering works as expected.
Download
The complete source code is available at https://github.com/machaoyin/SpringBoot-Security .
Java Architect Essentials
Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.