目录

SpringSecurity权限管理系统实战—一、项目简介和开发环境准备

SpringSecurity权限管理系统实战—二、日志、接口文档等实现

SpringSecurity权限管理系统实战—三、主要页面及接口实现

SpringSecurity权限管理系统实战—四、整合SpringSecurity(上)

SpringSecurity权限管理系统实战—五、整合SpringSecurity(下)

SpringSecurity权限管理系统实战—六、SpringSecurity整合jwt

SpringSecurity权限管理系统实战—七、处理一些问题

前言

博主的文笔有些差,大家多担待

一、简介

​ 在企业应用中,认证和授权是非常重要的一部分内容,业界最出名的两个框架就是大名鼎鼎的 Shiro和Spring Security。本次我选取的是和SpringBoot更好兼容的SpringSecurity。

二、什么是RBAC

​ RBAC是Role Based Access Control的缩写,是基于角色的访问控制。一般都是分为用户(user), 角色(role),权限(permission)三个实体,角色(role)和权限(permission)是多对多的 关系,用户(user)和角色(role)也是多对多的关系。用户(user)和权限(permission) 之间没有直接的关系,都是通过角色作为代理,才能获取到用户(user)拥有的权限。

​ 以下是RBAC0的模型

详细解释见

三、系统功能

  • 用户管理:提供用户的相关配置
  • 角色管理:对权限与菜单进行分配
  • 菜单管理:已实现菜单动态路由,后端可配置化,支持多级菜单
  • 字典管理:可维护常用一些固定的数据
  • 系统日志:记录用户操作日志与异常日志
  • SQL监控:采用druid 监控数据库访问性能
  • 代码生成:高灵活度生成前后端代码,减少大量重复的工作任务
  • 接口管理:方便统一查看管理接口

由于本系统是边开发写此文档的,所以可能上述的功能在后续的开发中会有删改。

四、环境搭建

本次系统非前后端分离项目,基于SpringBoot+Layui,后台模板选用的是Pear Admin Layui (我目前见过最漂亮的layui后台模板,放张图片让大家感受一下)

数据库设计

目前先这样,之后还会扩展。

在idea中新建SpringBoot项目,导入所需依赖


<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--这里需要先把SpringSecurity注销-->
<!-- <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>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!--swagger ui-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.7.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>

在项目中把架构搭好,创建对应数据库表的eneity、dao、service、controller,非常简单不想占用篇幅。需要注意的就是实体类中的create_time,和update_time,由于这两个和id是在多张表中都有出现,所以我们可以把它们抽离出来,有需要的实体类直接继承就可以了

@Data
public abstract class BaseEntity<ID extends Serializable> implements Serializable { private static final long serialVersionUID = 8925514045582235838L;
private ID id;
private Date createTime = new Date();
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime = new Date(); }

再插一嘴,@Data是lambok提供的一个注解,可以用于生成实体类的get和set方法。使用需要导入maven依赖,在idea中也要安装相应插件。如何安装使用使用详见

然后将PearAdmin的资源放入templates下

那么接下来我们先把项目运行起来,在index.html中加入thymeleaf的命名空间,通过thymeleaf的语法重新引入下资源。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" th:href="@{/PearAdmin/component/layui/css/layui.css}" />
<link rel="stylesheet" th:href="@{/PearAdmin/admin/css/pearTab.css}" />
<link rel="stylesheet" th:href="@{/PearAdmin/admin/css/pearTheme.css}" />
<link rel="stylesheet" th:href="@{/PearAdmin/admin/css/pearLoad.css}" />
<link rel="stylesheet" th:href="@{/PearAdmin/admin/css/pearFrame.css}" />
<link rel="stylesheet" th:href="@{/PearAdmin/admin/css/pearAdmin.css}" />
<link rel="stylesheet" th:href="@{/PearAdmin/admin/css/pearNotice.css}" />
<link rel="stylesheet" th:href="@{/PearAdmin/admin/css/pearSocial.css}" />
<link rel="stylesheet" th:href="@{/PearAdmin/admin/css/pearMenu.css}" /> <style id="pearone-bg-color"></style>
</head>
<body class="layui-layout-body pear-admin">
<!-- 布局框架 -->
<div class="layui-layout layui-layout-admin">
<div class="layui-header">
<ul class="layui-nav layui-layout-left">
<li class="collaspe layui-nav-item"><a href="#" class="layui-icon layui-icon-shrink-right"></a></li>
<li class="refresh layui-nav-item"><a href="#" class="layui-icon layui-icon-refresh-1"></a></li>
</ul>
<div id="control" class="layui-layout-control"></div>
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item layui-hide-xs"><a href="#" class="fullScreen layui-icon layui-icon-screen-full"></a></li>
<li class="layui-nav-item layui-hide-xs"><a href="http://www.pearadmin.cn" class="layui-icon layui-icon-website"></a></li>
<li class="layui-nav-item layui-hide-xs" id="headerNotice"></li>
<li class="layui-nav-item" lay-unselect="">
<a href="javascript:;"><img th:src="@{/PearAdmin/admin/images/avatar.jpg}" class="layui-nav-img">就眠仪式</a>
<dl class="layui-nav-child">
<dd><a href="javascript:;" class="pearson">个人信息</a></dd>
<dd><a href="javascript:;">安全配置</a></dd>
<dd><a href="login.html">注销登陆</a></dd>
</dl>
</li> <li class="setting layui-nav-item"><a href="#" class="layui-icon layui-icon-more-vertical"></a></li>
</ul>
</div>
<div class="layui-side layui-bg-black">
<div class="layui-logo">
<img class="logo" th:src="@{/PearAdmin/admin/images/logo.png}" />
<span class="title">Plus Admin</span>
</div>
<div class="layui-side-scroll">
<div id="sideMenu"></div>
</div>
</div>
<div class="layui-body">
<div id="content"></div>
</div>
</div>
<!-- 移动端 遮盖层 -->
<div class="pear-cover"></div>
<!-- 初始加载 动画-->
<div class="loader-main">
<div class="loader"></div>
</div>
<!-- 聊天组件 -->
<div id="social" class="layui-hide-xs"></div>
<!-- 移动端 的 收缩适配 -->
<div class="collaspe pe-collaspe layui-hide-sm">
<i class="layui-icon layui-icon-shrink-right"></i>
</div>
<script th:src="@{/PearAdmin/component/layui/layui.js}" charset="utf-8"></script>
<script>
layui.use(['pearAdmin', 'jquery', 'pearSocial', 'layer'], function() {
var pearAdmin = layui.pearAdmin;
var $ = layui.jquery;
var layer = layui.layer;
var pearSocial = layui.pearSocial;
var pearAuth = layui.pearAuth; var config = {
keepLoad: 2000, // 主 页 加 载 过 度 时 长 可为 false
muiltTab: true, // 是 否 开 启 多 标 签 页 true 开启 false 关闭
control: false, // 是 否 开 启 多 系 统 菜 单 true 开启 false 关闭
theme: "dark-theme", // 默 认 主 题 样 式 dark-theme 默认主题 light-theme 亮主题
index: '/console/console1', // 默 认 加 载 主 页,这里需要该
data: 'PearAdmin/admin/data/menu.json', // 菜 单 数 据 加 载 地 址
select: '0', // 默 认 选 中 菜 单 项
notice: 'PearAdmin/admin/data/notice.json', // 消 息 列 表 数 据
auth: 'PearAdmin/admin/data/permission.json' // 前端权限限制,false 关闭该功能
}; var setting = {
elem: 'social'
} pearSocial.render(setting);
pearAdmin.render(config);
})
</script>
</body>
</html>

因为这里默认的index界面是console1.html,所以console1.html里的资源和json也要重新引入,这里就不放出代码了。

Pear自带了一些json数据,这里我们先用他的,把路径改成自己项目的。新建一个HelloController,在里面配置下路由

@Controller
public class HelloController {
@GetMapping(value = "/console/console1")
@ApiOperation(value = "转发console1请求")
public String console1(){
return "console/console1";
} @GetMapping(value = "/system/organization")
public String organization(){
return "system/organization";
} @GetMapping(value = "/system/user")
public String user(){
return "system/user";
} @GetMapping(value = "/system/role")
public String role(){
return "system/role";
} @GetMapping(value = "/system/power")
public String power(){
return "system/power";
} @GetMapping(value = "/page/comment")
public String comment(){
return "page/comment";
}
}

我们启动项目,看一下效果

Pear的菜单是通过menu.json来动态生成的。之后的这个数据需要后端返回,但是我先用这个假数据。我把我修改过的menu.json贴上来,避免有些同学页面出不来。

[{
"id": 1,
"title": "工作空间",
"type": 0,
"icon": "layui-icon layui-icon-console",
"href": "",
"children": [{
"id": 0,
"title": "控制后台",
"icon": "layui-icon layui-icon-console",
"type": 1,
"openType": "_iframe",
"href": "console/console1"
}]
},
{
"id": 4,
"title": "系统管理",
"icon": "layui-icon layui-icon-set-fill",
"type": 0,
"href": "",
"children": [{
"id": 44,
"title": "部门管理",
"icon": "layui-icon layui-icon-username",
"type": 1,
"openType": "_iframe",
"href": "system/organization"
},{
"id": 41,
"title": "用户管理",
"icon": "layui-icon layui-icon-username",
"type": 1,
"openType": "_iframe",
"href": "system/user"
},
{
"id": 42,
"title": "角色管理",
"icon": "layui-icon layui-icon-user",
"type": 1,
"openType": "_iframe",
"href": "system/role"
},
{
"id": 43,
"title": "权限管理",
"icon": "layui-icon layui-icon-user",
"type": 1,
"openType": "_iframe",
"href": "system/power"
}
]
},
{
"id": 2,
"title": "扩展组件",
"icon": "layui-icon layui-icon-component",
"type": 0,
"href": "",
"children": [
{
"id": 22,
"title": "进阶组件",
"icon": "layui-icon layui-icon-face-smile",
"type": 0,
"href": "view/common/message.html",
"children": [
{
"id": 225,
"title": "卡片列表",
"icon": "layui-icon layui-icon-face-smile",
"type": 1,
"openType": "_iframe",
"href": "view/common/senior/card.html"
},
{
"id": 224,
"title": "树状结构",
"icon": "layui-icon layui-icon-face-smile",
"type": 1,
"openType": "_iframe",
"href": "view/common/senior/dtree.html"
}
]
}
]
},
{
"id": 3,
"title": "常用页面",
"icon": "layui-icon layui-icon-face-cry",
"type": 0,
"href": "",
"children": [{
"id": 302,
"title": "登录页面",
"icon": "layui-icon layui-icon-face-smile",
"type": 1,
"openType": "_iframe",
"href": "login"
},
{
"id": 303,
"title": "留言板",
"icon": "layui-icon layui-icon-face-smile",
"type": 1,
"openType": "_iframe",
"href": "page/comment"
}
]
},
{
"id": "error",
"title": "错误页面",
"icon": "layui-icon layui-icon-auz",
"type": 0,
"href": "",
"children": [{
"id": 403,
"title": "403",
"icon": "layui-icon layui-icon-face-smile",
"type": 1,
"openType": "_iframe",
"href": "view/error/403.html"
},
{
"id": 404,
"title": "404",
"icon": "layui-icon layui-icon-face-cry",
"type": 1,
"openType": "_iframe",
"href": "view/error/404.html"
}, {
"id": 500,
"title": "500",
"icon": "layui-icon layui-icon-face-cry",
"type": 1,
"openType": "_iframe",
"href": "view/error/500.html"
} ]
}
]

五、技术栈

将会涉及到的技术栈(待完善)

1、SpringBoot

2、SpringSecurity

3、MyBatis

4、Apache Log4j2

5、JWT

6、Druid

7、Swagger

8、Redis

9、Layui

10、Pear Admin Layui

六、说明

以上源代码同步在giteegithub中,如果可以的话,请给我一个star,谢谢

SpringSecurity权限管理系统实战—一、项目简介和开发环境准备的更多相关文章

  1. SpringSecurity权限管理系统实战—二、日志、接口文档等实现

    系列目录 SpringSecurity权限管理系统实战-一.项目简介和开发环境准备 SpringSecurity权限管理系统实战-二.日志.接口文档等实现 SpringSecurity权限管理系统实战 ...

  2. SpringSecurity权限管理系统实战—四、整合SpringSecurity(上)

    目录 SpringSecurity权限管理系统实战-一.项目简介和开发环境准备 SpringSecurity权限管理系统实战-二.日志.接口文档等实现 SpringSecurity权限管理系统实战-三 ...

  3. SpringSecurity权限管理系统实战—六、SpringSecurity整合jwt

    目录 SpringSecurity权限管理系统实战-一.项目简介和开发环境准备 SpringSecurity权限管理系统实战-二.日志.接口文档等实现 SpringSecurity权限管理系统实战-三 ...

  4. SpringSecurity权限管理系统实战—七、处理一些问题

    目录 SpringSecurity权限管理系统实战-一.项目简介和开发环境准备 SpringSecurity权限管理系统实战-二.日志.接口文档等实现 SpringSecurity权限管理系统实战-三 ...

  5. SpringSecurity权限管理系统实战—八、AOP 记录用户、异常日志

    目录 SpringSecurity权限管理系统实战-一.项目简介和开发环境准备 SpringSecurity权限管理系统实战-二.日志.接口文档等实现 SpringSecurity权限管理系统实战-三 ...

  6. SpringSecurity权限管理系统实战—九、数据权限的配置

    目录 SpringSecurity权限管理系统实战-一.项目简介和开发环境准备 SpringSecurity权限管理系统实战-二.日志.接口文档等实现 SpringSecurity权限管理系统实战-三 ...

  7. SpringSecurity权限管理系统实战—三、主要页面及接口实现

    系列目录 前言 后端五分钟,前端半小时.. 每次写js都头疼. 自己写前端是不可能的,这辈子不可能自己写前端的,只能找找别人的模板才能维持的了生存这样子.github,gitee上的模板又多,帮助文档 ...

  8. SpringSecurity权限管理系统实战—五、整合SpringSecurity(下)

    系列目录 前言 上篇文章SpringSecurity整合了一半,这次把另一半整完,所以本篇的序号接着上一篇. 七.自定义用户信息 前面我们登录都是用的指定的用户名和密码或者是springsecurit ...

  9. Scala语言简介和开发环境配置

    Scala语言的简介和开发环境搭建 Scala是一门结合了面向对象特征和函数式编程特征的语言,它是一个创新的编程语言产品.Scala可以做脚本(就像shell脚本一样),可以做服务端编程语言,可以写数 ...

随机推荐

  1. springAOP的三种实现方式

    springAOP的实现方式 三种 纯XML方式,XML+注解,纯注解方式. Spring 实现AOP思想使⽤的是动态代理技术 默认情况下, Spring会根据被代理对象是否实现接⼝来选择使⽤JDK还 ...

  2. EF批量插入太慢?那是你的姿势不对

    大概所有的程序员应该都接触过批量插入的场景,我也相信任何的程序员都能写出可正常运行的批量插入的代码.但怎样实现一个高效.快速插入的批量插入功能呢? 由于每个人的工作履历,工作年限的不同,在实现这样的一 ...

  3. Salt 系统初始化

    目录 编辑states文件 1.DNS配置  dns.sls(在init目录下创建一个files文件,然后把resolv.conf放到文件下) [root@master init]# cat dns. ...

  4. 两种 HTTP 方法:GET 和 POST

    区别 GET POST 可见性 数据在 URL 中对所有人都是可见的. post 方式通过body体进行传输,数据不会显示在 URL 中. 安全性 与 POST 相比,GET 的安全性较差,因为所发送 ...

  5. 初识ES数据库

    一.什么是Elasticsearch 1.概念以及特点 1.Elasticsearch和MongoDB/Redis/Memcache一样,是非关系型数据库. 是一个接近实时的搜索平台,从索引这个文档到 ...

  6. jmeter混合场景的多种实现方式比较

    性能测试设计混合场景,一般有几种方式,分别是每个场景设置一个线程组,使用if控制器,使用吞吐量控制器.不同的方式实现机制不一样,哪种方式相比而言更好呢?下面做一比较. 下面以混合访问百度首页和必应首页 ...

  7. 3-Pandas之Series和DataFrame区别

    一.Pandas pandas的数据元素包括以下几种类型: 类型 说明 object 字符串或混合类型 int 整型 float 浮点型 datetime 时间类型 bool 布尔型 二.Series ...

  8. PHP password_verify() 函数

    password_verify() 函数用于验证密码是否和散列值匹配. PHP 版本要求: PHP 5 >= 5.5.0, PHP 7高佣联盟 www.cgewang.com 语法 bool p ...

  9. 4.24 省选模拟赛 欧珀瑞特 主席树 可持久化trie树

    很容易的一道题目.大概.不过我空间计算失误MLE了 我草草的计算了一下没想到GG了. 关键的是 我学了一个dalao的空间回收的方法 但是弄巧成拙了. 题目没有明确指出 在任意时刻数组长度为有限制什么 ...

  10. php+mysql+apache实现登录注册系统

    Php+mysql写网页注册登录系统 1.搭建msyql+php+apache的网站环境 (1) 在云服务器上搭建服务器,推荐使用宝塔集成 (2) 在本地windows搭建,推荐自己采用分开安装,这样 ...