微服务迁移记(五):WEB层搭建(4)-简单的权限管理
一、redis搭建
二、WEB层主要依赖包
三、FeignClient通用接口
以上三项,参考《微服务迁移记(五):WEB层搭建(1)》
四、SpringSecurity集成
参考:《微服务迁移记(五):WEB层搭建(2)-SpringSecurity集成》
五、FreeMarker集成
参考:《微服务迁移记(五):WEB层搭建(3)-FreeMarker集成》
六、简单权限管理
实现一个简单的到按钮级权限管理,基于数据库扩展。不支持数据级权限,菜单只到二级(可以扩展至无限级,一般MIS系统,三级应该够了)
1. 数据库设计
用户表:tb_user
角色表:tb_role
用户角色:tb_user_role,外键:user_id,role_id
菜单表:tb_tree
菜单功能按钮表:tb_tree_func,外键:tree_id
角色菜单权限:tb_role_right(应该叫tb_role_tree更合适点),外键:role_id,tree_id
角色菜单下功能按钮:tb_roletree_func,外键:role_right_id,tree_id,role_tree_func(这个键没有拉外键过来),三个外键组成联合主键。
外键关系见下图
2. 用户登录后,左侧二级菜单展示
数据源:获取所有菜单及按钮的权限,前文提到的SpringSecurity里,MyUserDetail里我加过一个roletree的字段,会一起扔到session里(用户更换权限后,需要退出重新登录才能生效)
//获取所有树及按钮,含当前角色是否有权限
public Map<String,Object> getAllTreeWithRoleRight(int role_id){
String sql = "SELECT a.tree_id,a.tree_name,a.sup_tree_id,a.taxis,IFNULL(b.tree_id,0) as perm FROM " +
" tb_tree a left JOIN " +
"(SELECT rr.tree_id FROM tb_role_right rr " +
"WHERE rr.role_id=?) b " +
"ON b.tree_id=a.tree_id " +
" WHERE a.del_flag=0 AND enable_flag=1 " +
" ORDER BY sup_tree_id ASC,taxis ASC;";
List<Map<String,Object>> tree = this.jdbcTemplate.queryForList(sql,role_id);
//再查询所有按钮
sql = "SELECT a.tree_id,b.tree_func_name,b.tree_func_namedesc,IFNULL(c.tree_id,0) as perm FROM tb_tree a INNER JOIN tb_tree_func b ON b.tree_id=a.tree_id " +
"left JOIN " +
"(SELECT rt.tree_id,rt.role_id,rt.tree_func_name FROM tb_role_treefunc rt WHERE rt.role_id=?) c " +
"ON c.tree_id=a.tree_id AND c.tree_func_name=b.tree_func_name";
List<Map<String,Object>> func = jdbcTemplate.queryForList(sql,role_id);
Map<String,Object> map = new HashMap<String,Object>();
map.put("tree",tree);
map.put("func",func);
return map;
}
freemarker前台展示二级菜单:
<div id="sidebar-collapse" class="col-sm-3 col-lg-2 sidebar">
<ul class="nav menu">
<li class="active"><a href="javascript:goto('0000','/home');"><span class="glyphicon glyphicon-home"></span> 首页</a></li>
<#list treelist as tree>
<#if tree.sup_tree_id == >
<li class="parent ">
<a data-toggle="collapse" href="#sub-item-${tree.tree_id?c}">
<span class="glyphicon ${tree.tree_icon}"></span> ${tree.tree_name}
</a>
<ul class="children collapse" id="sub-item-${tree.tree_id?c}">
<#list treelist as tree_c>
<#if tree_c.sup_tree_id==tree.tree_id>
<li><a href="javascript:goto(${tree_c.tree_id?c},'${tree_c.link_addr!}')"><span class="glyphicon ${tree_c.tree_icon}"></span> ${tree_c.tree_name}</a></li>
</#if>
</#list>
</ul>
</li>
</#if>
</#list>
<li role="presentation" class="divider"></li>
<li><a href="/manage/Login/logout"><span class="glyphicon glyphicon-user"></span> 注销</a></li>
</ul>
</div><!--/.sidebar-->
最终展示效果如下:
2. 模块中按钮权限控制
通过自定义FreeMarker标签,实现前台按钮展示或隐藏
PermissionTagDirective 继承自TemplateDirectiveModel ,引用时需要传递tree_id和permissiontype两个字段进来。
package com.zyproject.web.freemarker; import com.zyproject.entity.RoleTreefuncEntity;
import com.zyproject.entity.UserEntity;
import com.zyproject.web.secrity.MyUserDetails;
import freemarker.core.Environment;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component; import java.io.IOException;
import java.util.List;
import java.util.Map; /**
* @program: zyproject
* @description: freemarker自定义标签,实现按钮级权限控制
* @author: zhouyu(zhouyu629 # qq.com)
* @create: 2020-02-18
**/
@Component
public class PermissionTagDirective implements TemplateDirectiveModel {
private static String permissionType = "ptype"; //A新增,D删除等,与数据库对应
private static String Tree = "tree_id"; //菜单id
@Override
public void execute(Environment environment, Map map,
TemplateModel[] templateModels,
TemplateDirectiveBody templateDirectiveBody) throws TemplateException, IOException {
String ptype = map.get(permissionType).toString();
String tree_id = map.get(Tree).toString();
//当前登录用户
MyUserDetails myUserDetails = (MyUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
//判断权限,当前tree下,是否有ptype权限
if(this.checkRight(myUserDetails.getTreefuncEntities(),ptype,tree_id)) {
templateDirectiveBody.render(environment.getOut());
}
} private boolean checkRight(List<RoleTreefuncEntity> roleTreefuncEntities,String ptype,String tree_id){
for (RoleTreefuncEntity roleTreefuncEntity :roleTreefuncEntities) {
if(roleTreefuncEntity.getTree_id() == Integer.valueOf(tree_id) && roleTreefuncEntity.getTree_func_name().equals(ptype)){
return true;
}
}
return false;
}
}
然后把这个标签注册到FreeMarker
package com.zyproject.web.freemarker; import freemarker.template.Configuration;
import freemarker.template.TemplateException;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component; import javax.annotation.PostConstruct;
import java.io.IOException; /**
* @program: zyproject
* @description: 注册标签到Freemarker
* @author: zhouyu(zhouyu629 # qq.com)
* @create: 2020-02-18
**/
@Component
public class CustomeFreemakerConfigure implements ApplicationContextAware {
@Autowired
Configuration configuration; @Autowired
private PermissionTagDirective permissionTagDirective; @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { } @PostConstruct
public void setSharedVariable() throws IOException, TemplateException{
configuration.setSharedVariable("perm",permissionTagDirective);
}
}
前台引用标签,标签里的参数tree_id,是在BaseController里扔到前台的,所有Controller都继承自BaseController(这部分代码略)
<@perm tree_id="${tree_id}" ptype="M">
<button name="btnModify" onclick="edit(${roles.role_id})" type="button" class="btn btn-primary btn-sm"><span class="glyphicon glyphicon-th" aria-hidden="true"></span>修改</button>
</@perm>
<@perm tree_id="${tree_id}" ptype="D">
<button name="btnDel" type="button" onclick="del(${roles.role_id})" class="btn btn-danger btn-sm"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span>删除</button>
</@perm>
<@perm tree_id="${tree_id}" ptype="R">
<button name="btnRight" type="button" onclick="setRight(${roles.role_id})" class="btn btn-success btn-sm"><span class="glyphicon glyphicon-tags" aria-hidden="true"></span>权限</button>
</@perm>
最终展示效果如下,后面三个按钮根据角色权限分配得来:
待完善:
1. BaseController里还要判断下进入每个模块是否有相应的权限,防止用户通过直接输入url地址绕过自定义标签的判断
2. 目前权限只到菜单和按钮级别,如果这个功能模块有多个子界面,权限都跟主界面保持一致
微服务迁移记(五):WEB层搭建(4)-简单的权限管理的更多相关文章
- 微服务迁移记(五):WEB层搭建(5)-集成ueditor编辑器,伪分布式图片上传
一.redis搭建 二.WEB层主要依赖包 三.FeignClient通用接口 以上三项,参考<微服务迁移记(五):WEB层搭建(1)> 四.SpringSecurity集成 参考:< ...
- 微服务迁移记(五):WEB层搭建(2)-SpringSecurity集成
一.redis搭建 二.WEB层主要依赖包 三.FeignClient通用接口 以上三项,参考<微服务迁移记(五):WEB层搭建(1)> 接下来,集成SpringSecruity,实现用户 ...
- 微服务迁移记(五):WEB层搭建(3)-FreeMarker集成
一.redis搭建 二.WEB层主要依赖包 三.FeignClient通用接口 以上三项,参考<微服务迁移记(五):WEB层搭建(1)> 四.SpringSecurity集成 参考:< ...
- 微服务迁移记(五):WEB层搭建(1)
WEB层是最终表现层,注册至注册中心,引用接口层(不需要引用实现层).公共服务层.用户登录使用SpringSecurity,Session保存在redis中,权限管理没有用SpringSecurity ...
- docker微服务部署之:二、搭建文章微服务项目
docker微服务部署之:一,搭建Eureka微服务项目 一.新增demo_article模块,并编写代码 右键demo_parent->new->Module->Maven,选择M ...
- docker微服务部署之:三,搭建Zuul微服务项目
docker微服务部署之:二.搭建文章微服务项目 一.新增demo_eureka模块,并编写代码 右键demo_parent->new->Module->Maven,选择Module ...
- docker微服务部署之:一,搭建Eureka微服务项目
先说明一下docker需要搭建的微服务的基本情况: 项目情况:一个demo_parent项目,下面三个子模块:demo_eureka(eureka服务).demo_article(文章服务).demo ...
- 微服务实践(五):微服务的事件驱动数据管理 - DockOne.io
原文:微服务实践(五):微服务的事件驱动数据管理 - DockOne.io [编者的话]本文是使用微服务创建应用系列的第五篇文章.第一篇文章介绍了微服务架构模式,并且讨论了使用微服务的优缺点:第二和第 ...
- 微服务(入门四):identityServer的简单使用(客户端授权)
IdentityServer简介(摘自Identity官网) IdentityServer是将符合规范的OpenID Connect和OAuth 2.0端点添加到任意ASP.NET核心应用程序的中间件 ...
随机推荐
- STL标准函数库学习小总结
浅谈STL(未完)前言:(1)学习资料——<算法笔记>第六章.<常用基础数据结构>文档 (2)测试平台——Codeup新家(<算法笔记>对应OJ).洛谷.YCOJ ...
- 阿里云centos7安装redis全过程记录
Redis下载地址:https://redis.io/download(这个连接可能得翻墙查看,但是在centos7服务器上安装过程不需要翻墙,我查看了最新的是redis-4.0.9.tar.gz ) ...
- HBase2.0 meta信息丢失的修复方法
在HBase入库日志中发现有一个表入库失败,检查HBase服务端后发现该表的meta信息丢失了: 而HDFS上的region还在: 而HBCK工具不支持HBase2.0版本,只好自己写一个修复工具.网 ...
- 奇怪DP之步步为零
题目 思路 很明显的dp就是不会跑啊,所以最后dfs救了一下场,不出所料,最后果然T了,现在说一下正解. 为什么说是奇怪dp呢,这道题的dp数组是布尔型的,f[i][j][k]代表在到第i行第j列之前 ...
- 线性动归之Wooden Sticks
题面:现在有n(n<5000)个木头,每个木头都有长度l和重量w(l<10000,w<10000),现在你要对木头进行加工: 1.第一根木头需要先花费1min: 2.加工完第i跟木头 ...
- 如何科学地完成一场 AR 发布会?全在这份超细节活动策划 Xmind 里了
你们在哪个酒店搭的景? 5 月 28 日,网易智慧企业完成了一场实景人物拍摄 + 虚拟舞台渲染的 AR 线上见面会.非常有趣的是,在直播过程中,不止一位观众问我们,“你们是在哪个酒店搭的景?”.看来我 ...
- 蜂鸟E203系列——Linux开发工具
欲观原文,请君移步 Vivado安装 vivado是运行工程的工具,所以必须安装 后台回复[vivado2017]可获取vivado 2017.4 | 后台回复[vivado2020]可获取vitis ...
- Centos 6.4最小化安装后的优化(1)
一.更新yum官方源 Centos 6.4系统自带的更新源速度比较慢,相比各位都有所感受,国内的速度慢的让人受不了.为了让centos6.4系统使用速度更快的yum更新源,一般都会选择更换源,详细步骤 ...
- Let's GO(一)
近来开始学Go,留此博客以记录学习过程,顺便鞭策自己更加努力. 人生苦短,Let's GO! Let's GO(一) Let's GO(二) Let's GO(三) Let's GO(四) 简单介绍 ...
- Scala 面向对象(八):特质(接口) 一
1 Scala接口的介绍 从面向对象来看,接口并不属于面向对象的范畴,Scala是纯面向对象的语言,在Scala中,没有接口. Scala语言中,采用特质trait(特征)来代替接口的概念,也就是说, ...