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

目录

SpringSecurity权限管理系统实战—一、项目简介和开发环境准备
SpringSecurity权限管理系统实战—二、日志、接口文档等实现
SpringSecurity权限管理系统实战—三、主要页面及接口实现
SpringSecurity权限管理系统实战—四、整合SpringSecurity(上)
SpringSecurity权限管理系统实战—五、整合SpringSecurity(下)
SpringSecurity权限管理系统实战—六、SpringSecurity整合jwt
SpringSecurity权限管理系统实战—七、处理一些问题
SpringSecurity权限管理系统实战—八、AOP记录用户、异常日志
SpringSecurity权限管理系统实战—九、数据权限的配置

前言

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

一、简介

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

二、什么是RBAC

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

​ 以下是RBAC0的模型

rbac.png

详细解释见

三、系统功能

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

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

四、环境搭建

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

![sql.png](https://upload-images.jianshu.io/upload_images/13222772-0141bb1fc1fd8376.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

数据库设计

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

在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下

templates.png

那么接下来我们先把项目运行起来,在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";
    }
}

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


index.png

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,谢谢

七、目前已完成

Admin端
image text
image text
image text
image text
image text
image text
image text
image text
image text
image text
image text
image text
image text
image text
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,290评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,107评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,872评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,415评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,453评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,784评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,927评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,691评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,137评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,472评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,622评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,289评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,887评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,316评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,490评论 2 348