Build a Secure Permission System with SpringBoot, MyBatis & Shiro
This article introduces the open‑source renren‑security permission management solution, detailing its architecture, core modules, and how to implement authentication and authorization with Apache Shiro in a SpringBoot‑MyBatis stack, including code examples for login, role‑based access, XSS/SQL filtering, and deployment options.
System security is a non‑negotiable aspect of software development, and permission control is tightly coupled with it. The open‑source renren‑security project provides a lightweight permission management system built with SpringBoot, MyBatis, and Apache Shiro, offering low entry barriers and ready‑to‑use features such as distributed deployment, Quartz clustering, department management, data permissions, and cloud storage.
Project Features
Fine‑grained permission control down to pages or buttons, covering most use cases.
Comprehensive department and data‑level permissions implemented via annotations.
Robust XSS protection and script filtering to prevent attacks.
Support for major databases: MySQL, Oracle, SQL Server, PostgreSQL, etc.
System Architecture
The system is organized into clear modules: common , admin , and api .
common : A jar‑based library shared by other modules, providing utilities such as time handling, pagination, SQL filtering, XSS filtering, Redis aspects, and custom exception handling.
admin : The management console packaged as a WAR, following a front‑end/back‑end separation model. It includes user, role, department, menu management, scheduled tasks, file upload, API validation, and Redis caching, supporting both single‑node and cluster deployments.
api : The API layer, also packaged as a WAR, exposing endpoints for front‑end UI calls. It handles user registration, login, permission verification, and user information retrieval, and integrates Swagger2 for API documentation.
The design emphasizes security: both pages and APIs perform permission checks via Shiro. During login, the user’s credentials are validated, roles are retrieved, and Shiro enforces access control on UI elements and API calls. SQL and XSS filtering are applied before persisting data.
Shiro Authentication and Authorization
Authentication requires a custom Realm extending AuthorizingRealm and overriding doGetAuthenticationInfo (for login) and doGetAuthorizationInfo (for permission retrieval).
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
subject.login(token); // triggers Shiro authentication
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
SysUserEntity user = new SysUserEntity();
user.setUsername(token.getUsername());
user = sysUserDao.selectOne(user);
if (user == null) {
throw new UnknownAccountException("账号或密码不正确");
}
return new SimpleAuthenticationInfo(user, user.getPassword(), ByteSource.Util.bytes(user.getSalt()), getName());
}After successful authentication, SecurityUtils.getSubject() can retrieve the authenticated user anywhere in the system, enabling features such as automatic login.
Permissions are stored as tags in the database; a user possessing a tag gains the corresponding operation rights. During authorization, the system loads all permission tags for the user and builds a SimpleAuthorizationInfo object.
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SysUserEntity user = (SysUserEntity) principals.getPrimaryPrincipal();
Long userId = user.getUserId();
Set<String> permsSet = new HashSet<>();
List<String> permsList = sysUserDao.queryAllPerms(userId);
for (String perms : permsList) {
if (StringUtils.isBlank(perms)) continue;
permsSet.addAll(Arrays.asList(perms.trim().split(",")));
}
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setStringPermissions(permsSet);
return info;
}Shiro’s permission checks can be applied at two levels:
Page level : Using #if shiro.hasPermission("sys:del") in templates to conditionally render buttons or links.
Method level : Annotating controller methods with @RequiresPermissions("sys:del") to enforce access control.
<#if shiro.hasPermission("sys:add")>
<a class="btn btn-primary" @click="add">新增</a>
</#if>
<#if shiro.hasPermission("sys:del")>
<a class="btn btn-primary" @click="del">删除</a>
</#if> @RequestMapping("/delete")
@RequiresPermissions("sys:del")
public R delete(long deptId) {
List<Long> deptList = sysDeptService.queryDetpIdList(deptId);
if (deptList.size() > 0) {
return R.error("请先删除子部门");
}
sysDeptService.deleteById(deptId);
return R.ok();
}Beyond permission control, the project also includes common backend features such as Quartz distributed scheduling, dynamic multi‑data‑source switching, and clustered session management. The source code is available at https://gitee.com/renrenio/renren-security .
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
21CTO
21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.
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.
