最近在公司里做了一个基于用户角色的页面路由资源权限控制的需求,前后端分离结合起来难度还是挺大的,去年也做过一个类似的需求,把前后端打通花了好天时间。当时就想写一篇关于权限控制的实战文章,但是无奈数据属于公司的保密级别,不好造数据就搁浅了。
如果仅仅是限制后台接口的权限或者前端路由列表是静态的,每次添加新的页面就往路由文件里加路由组件,那样实现起来倒是没什么挑战。后台用spring-security
或者shiro
可以搞定,前端使用vue-router
可轻松搞定。现在的需求是要求用户登录后根据其角色加载具有权限的页面和可访问的路由列表,就是要求动态加载系统左侧的菜单。后面的权限控制页面要求能给用户分配角色、给角色动态添加页面权限等都涉及到了前后端结合控制用户的对资源和按钮的访问权限。
对于精通java
的开发人员来说,这样的需求后台的难度不是很大,前端结合vuex
和vue-router
从后台取数据实现动态页面路由跳转权限控制才是一大难点。限于文章篇幅,本文先解决后台有关权限控制的建表和接口需求,下一篇文章再结合前端vuex
和vue-router
组件实现完整的需求,并在页面上看到效果。
这篇文章以笔者上一篇文章介绍一个开源博客项目VBlog并打包部署到已存在运行项目的Nginx服务器下 为基础,大部分表已建好,只需要再添加两张与实现权限控制需求相关的表。
-- 建表脚本
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(64) DEFAULT NULL,
`nickname` varchar(64) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`enabled` tinyint(1) DEFAULT '1',
`email` varchar(64) DEFAULT NULL,
`userface` varchar(255) DEFAULT NULL,
`regTime` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8;
-- 添加数据
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('6', 'linghu', '令狐葱', '202cb962ac59075b964b07152d234b70', '1', 'linghu@qq.com', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1514093920326&di=44a6fa6b597d86f475c2b15fa93008dd&imgtype=0&src=http%3A%2F%2Fwww.qqzhi.com%2Fuploadpic%2F2015-01-12%2F023019564.jpg', '2017-12-08 09:30:22');
INSERT INTO `user` VALUES ('7', 'sang', '江南一点雨', '202cb962ac59075b964b07152d234b70', '1', ' sang123@qq.com', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1514093920321&di=913e88c23f382933ef430024afd9128a&imgtype=0&src=http%3A%2F%2Fp.3761.com%2Fpic%2F9771429316733.jpg', '2017-12-21 13:30:29');
INSERT INTO `user` VALUES('10', 'qiaofeng', '乔峰', '202cb962ac59075b964b07152d234b70', '1', 'qiaofeng@qq.com', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1514093920321&di=913e88c23f382933ef430024afd9128a&imgtype=0&src=http%3A%2F%2Fp.3761.com%2Fpic%2F9771429316733.jpg', '2017-12-24 06:30:46');
INSERT INTO `user` VALUES ('13', 'duanzhengchun', '段正淳', '202cb962ac59075b964b07152d234b70', '0', 'duanzhengchun@qq.com', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1514093920321&di=913e88c23f382933ef430024afd9128a&imgtype=0&src=http%3A%2F%2Fp.3761.com%2Fpic%2F9771429316733.jpg', '2017-12-24 06:30:46');
INSERT INTO `user` VALUES ('14', 'chenjialuo', '陈家洛', '202cb962ac59075b964b07152d234b70', '0', 'chenjialuo@qq.com', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1514093920321&di=913e88c23f382933ef430024afd9128a&imgtype=0&src=http%3A%2F%2Fp.3761.com%2Fpic%2F9771429316733.jpg', '2017-12-24 06:30:46');
INSERT INTO `user` VALUES ('15', 'yuanchengzhi', '袁承志', '202cb962ac59075b964b07152d234b70', '1', 'yuanchengzhi@qq.com', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1514093920321&di=913e88c23f382933ef430024afd9128a&imgtype=0&src=http%3A%2F%2Fp.3761.com%2Fpic%2F9771429316733.jpg', '2017-12-24 06:30:46');
INSERT INTO `user` VALUES ('16', 'chuliuxiang', '楚留香', '202cb962ac59075b964b07152d234b70', '1', 'chuliuxiang@qq.com', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1514093920321&di=913e88c23f382933ef430024afd9128a&imgtype=0&src=http%3A%2F%2Fp.3761.com%2Fpic%2F9771429316733.jpg', '2017-12-24 06:30:46');
INSERT INTO `user` VALUES ('17', 'baizhantang', '白展堂', '202cb962ac59075b964b07152d234b70', '0', 'baizhantang@qq.com', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1514093920321&di=913e88c23f382933ef430024afd9128a&imgtype=0&src=http%3A%2F%2Fp.3761.com%2Fpic%2F9771429316733.jpg', '2017-12-24 06:30:46');
INSERT INTO `user` VALUES ('18', 'renwoxing', '任我行', '202cb962ac59075b964b07152d234b70', '1', 'renwoxing@qq.com', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1514093920321&di=913e88c23f382933ef430024afd9128a&imgtype=0&src=http%3A%2F%2Fp.3761.com%2Fpic%2F9771429316733.jpg', '2017-12-24 06:30:46');
INSERT INTO `user` VALUES ('19', 'zuolengchan', '左冷禅', '202cb962ac59075b964b07152d234b70', '1', 'zuolengchan@qq.com', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1514093920321&di=913e88c23f382933ef430024afd9128a&imgtype=0&src=http%3A%2F%2Fp.3761.com%2Fpic%2F9771429316733.jpg', '2017-12-24 06:30:46');
INSERT INTO `user` VALUES('20', 'fengqingyang', '风清扬', '202cb962ac59075b964b07152d234b70', '1', 'fengqingyang@qq.com', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1514093920321&di=913e88c23f382933ef430024afd9128a&imgtype=0&src=http%3A%2F%2Fp.3761.com%2Fpic%2F9771429316733.jpg', '2017-12-24 06:30:46');
该表项目中原有,无需新建
-- 建表脚本,为了方便路由资源表关联角色表,该表需要修改
DROP TABLE IF EXISTS `roles`;
CREATE TABLE `roles` (
`id` int(11) NOT NULL AUTO_INCREMENT comment '角色ID',
role_code varchar(30) null comment '角色编码'
role_name varchar(32) null comment '角色名称',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
-- Records of roles
-- ----------------------------
INSERT INTO roles(role_code,role_name) VALUES ('superAdmin', '超级管理员');
INSERT INTO roles(role_code,role_name) VALUES ('generalUser', '普通用户');
INSERT INTO roles(role_code,role_name) VALUES ('test1', '测试角色1');
INSERT INTO roles(role_code,role_name) VALUES ('test2', '测试角色2');
INSERT INTO roles(role_code,role_name) VALUES ('test3', '测试角色3');
该表可先删除,再新建
DROP TABLE IF EXISTS `roles_user`;
CREATE TABLE `roles_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`rid` int(11) DEFAULT '2',
`uid` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `rid` (`rid`),
KEY `roles_user_ibfk_2`(`uid`),
CONSTRAINT `roles_user_ibfk_1` FOREIGN KEY(`rid`) REFERENCES `roles`(`id`),
CONSTRAINT `roles_user_ibfk_2` FOREIGN KEY(`uid`) REFERENCES `user`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=131 DEFAULT CHARSET=utf8;
-- Records of roles_user
-- ----------------------------
INSERT INTO `roles_user` VALUES('8', '2', '7');
INSERT INTO `roles_user` VALUES('9', '1', '7');
INSERT INTO `roles_user` VALUES('17', '5', '7');
INSERT INTO `roles_user` VALUES('106', '2', '14');
INSERT INTO `roles_user` VALUES('108', '2', '16');
INSERT INTO `roles_user` VALUES('109', '2', '17');
INSERT INTO `roles_user` VALUES('110', '2', '18');
INSERT INTO `roles_user` VALUES('111', '2', '19');
INSERT INTO `roles_user` VALUES('112', '2', '20');
INSERT INTO `roles_user` VALUES('119', '2', '15');
INSERT INTO `roles_user` VALUES('120', '5', '15');
INSERT INTO `roles_user` VALUES('121', '2', '6');
INSERT INTO `roles_user` VALUES('123', '2', '13');
INSERT INTO `roles_user` VALUES('124', '3', '13');
INSERT INTO `roles_user` VALUES('128', '2', '10');
INSERT INTO `roles_user` VALUES('129', '5', '10');
INSERT INTO `roles_user` VALUES('130', '1', '6');
该表项目中原有,无需新建
drop table if exists router_resources;
create table router_resources(
id int auto_increment comment '主键',
pid int comment '父路由ID',
name varchar(50) not null comment '路由名称',
title varchar(50) comment '路由展示名称',
icon varchar(20) comment '图标',
hidden smallint comment '是否隐藏:0-展示;1-隐藏',
level smallint comment '层级',
path varchar(100) comment '路径',
componnet_url varchar(200) not null comment '组件完整url',
order_no int comment '顺序号',
keep_alive smallint not null default 0,
created_by varchar(64) not null comment '创建人',
created_time TIMESTAMP not null comment '创建时间',
last_updated_by varchar(64) comment '最后更新人',
last_updated_time TIMESTAMP comment '更新时间',
primary key (id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8 comment '路由资源表';
insert into router_resources(pid,name,title,icon,hidden,level,path,componnet_url,order_no,created_by,created_time)
values(0,'articleManagement','文章管理','fa fa-file-text-o',0,1,'/home','@/components/Home',1,'sang',now());
insert into router_resources(pid,name,title,icon,hidden,level,path,componnet_url,order_no,created_by,created_time)
values(0,'userManagement','用户管理','fa fa-user-o',0,1,'/home','@/components/Home',2,'sang',now());
insert into router_resources(pid,name,title,icon,hidden,level,path,componnet_url,order_no,created_by,created_time)
values(0,'categoriesManagement','栏目管理','fa fa-reorder',0,1,'/home','@/components/Home',3,'sang',now());
insert into router_resources(pid,name,title,icon,hidden,level,path,componnet_url,order_no,created_by,created_time)
values(0,'dataStatics','数据统计','fa fa-bar-chart',0,1,'/home','@/components/Home',4,'sang',now());
insert into router_resources(pid,name,title,icon,hidden,level,
path,componnet_url,order_no,created_by,created_time,
last_updated_by,last_updated_time,keep_alive)
values(1,'articleList','文章列表','',0,2,'/articleList','@/components/ArticleList',11,
'sang',now(),'sang',now(),1);
insert into router_resources(pid,name,title,icon,hidden,level,
path,componnet_url,order_no,created_by,created_time,
last_updated_by,last_updated_time,keep_alive)
values(1,'publishArticle','发表文章','',0,2,'/postArticle','@/components/PostArticle',12,
'sang',now(),'sang',now(),0);
insert into router_resources(pid,name,title,icon,hidden,level,
path,componnet_url,order_no,created_by,created_time,
last_updated_by,last_updated_time,keep_alive)
values(1,'blogDetail','博客详情','',1,2,'/blogDetail','@/components/BlogDetail',13,
'sang',now(),'sang',now(),0);
insert into router_resources(pid,name,title,icon,hidden,level,
path,componnet_url,order_no,created_by,created_time,
last_updated_by,last_updated_time,keep_alive)
values(1,'editBlog','编辑博客','',1,2,'/editBlog','@/components/PostArticle',14,
'sang',now(),'sang',now(),0);
insert into router_resources(pid,name,title,icon,hidden,level,
path,componnet_url,order_no,created_by,created_time,
last_updated_by,last_updated_time,keep_alive)
values(2,'userManagement','用户管理','fa fa-user-o',0,2,'/user','@/components/UserMana',21,
'sang',now(),'sang',now(),0);
insert into router_resources(pid,name,title,icon,hidden,level,
path,componnet_url,order_no,created_by,created_time,
last_updated_by,last_updated_time,keep_alive)
values(3,'cateManagement','栏目管理','fa fa-reorder',0,2,'/cateMana','@/components/CateMana',31,
'sang',now(),'sang',now(),0);
insert into router_resources(pid,name,title,icon,hidden,level,
path,componnet_url,order_no,created_by,created_time,
last_updated_by,last_updated_time,keep_alive)
values(4,'dataStatics','数据统计','fa fa-bar-chart',0,2,'/charts','@/components/DataCharts',41,
'sang',now(),'sang',now(),0);
路由资源表是根据前端vueblog
项目src/router/index.js
中路由项来定义字段
create table role_resources(
id int(11) not null auto_increment comment '主键',
role_id int(11) not null comment '角色ID',
resource_id int(11) not null comment '资源ID',
created_by varchar(64) not null comment '创建人',
created_time TIMESTAMP not null comment '创建时间',
last_updated_by varchar(64) comment '最后更新人',
last_updated_time TIMESTAMP comment '更新时间',
primary key (id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 使用root用户完成添加联合唯一索引
create unique index uk_role_resource on role_resources(role_id,resource_id);
insert into role_resources(role_id, resource_id, created_by, created_time, last_updated_by, last_updated_time)
values(7,1,'sang',now(),'sang',now());
insert into role_resources(role_id, resource_id, created_by, created_time, last_updated_by, last_updated_time)
values(7,2,'sang',now(),'sang',now());
insert into role_resources(role_id, resource_id, created_by, created_time, last_updated_by, last_updated_time)
values(7,3,'sang',now(),'sang',now());
insert into role_resources(role_id, resource_id, created_by, created_time, last_updated_by, last_updated_time)
values(7,4,'sang',now(),'sang',now());
insert into role_resources(role_id, resource_id, created_by, created_time, last_updated_by, last_updated_time)
values(7,5,'sang',now(),'sang',now());
insert into role_resources(role_id, resource_id, created_by, created_time, last_updated_by, last_updated_time)
values(7,6,'sang',now(),'sang',now());
insert into role_resources(role_id, resource_id, created_by, created_time, last_updated_by, last_updated_time)
values(7,7,'sang',now(),'sang',now());
insert into role_resources(role_id, resource_id, created_by, created_time, last_updated_by, last_updated_time)
values(7,8,'sang',now(),'sang',now());
insert into role_resources(role_id, resource_id, created_by, created_time, last_updated_by, last_updated_time)
values(7,9,'sang',now(),'sang',now());
insert into role_resources(role_id, resource_id, created_by, created_time, last_updated_by, last_updated_time)
values(7,10,'sang',now(),'sang',now());
insert into role_resources(role_id, resource_id, created_by, created_time, last_updated_by, last_updated_time)
values(7,11,'sang',now(),'sang',now());
新建表
为实现权限控制,在数据库中建了5张用于控制权限的表,分别是User表、Roles表、roles_user表、router_resources表和role_resources表,其中roles_user表中用户与角色是多对多的关系,role_resources表中角色与菜单资源也是多对多的关系。
RouterResource
与 RouterResourceVo
public class RouterResource implements Serializable {
private Integer id;
private Integer pid;
private String name;
private String title;
private String icon;
private Integer hidden;
private Integer level;
private String path;
private String componentUrl;
private Integer orderNo;
private String createdBy;
private Date createdTime;
private String lastUpdatedBy;
private Date lastUpdatedTime;
private Integer keepAlive;
// ......省略setter和gettter方法
}
public class RouterResourceVo implements Serializable {
// 主键ID
private Integer id;
// 路由资源名称
private String name;
// 路由资源标题
private String title;
// 路由资源图标(也可以称菜单图标)
private String icon;
// 是否隐藏:0-false;1-true
private boolean hidden;
// 菜单所在层级
private Integer level;
// 菜单路径
private String path;
// 菜单组件全路径
private String componentUrl;
// 是否keepAlive:0-false;1-true
private boolean keepAlive;
// 子节点集合
private List<RouterResourceVo> children = new ArrayList<>();
// ......省略setter和gettter方法
}
RoleRouterMapper.java
@Repository
public interface RoleRouterMapper {
// 根据角色ID查询角色下的路由资源列表
List<RouterResource> queryRoutersByRoleId(Integer roleId);
}
RoleRouterMapper.xml
<select id="queryRoutersByRoleId" parameterType="Integer" resultType="org.sang.bean.RouterResource">
SELECT id,pid,name,title,icon,hidden,level,path,
componnet_url as componentUrl,order_no as orderNo,
keep_alive as keepAlive
FROM router_resources
WHERE id in (
select resource_id from role_resources
where role_id=#{roleId,jdbcType=INTEGER}
)
ORDER BY level
</select>
@Service
public class RoleRouterService {
@Autowired
private RoleRouterMapper roleRouterMapper;
public List<RouterResourceVo> queryRoleRoutersByRoleId(Integer roleId){
List<RouterResourceVo> routerResourceVos = new ArrayList<>();
List<RouterResource> routerResources = roleRouterMapper.queryRoutersByRoleId(roleId);
if(routerResources.size()==0){
return routerResourceVos;
}
Integer maxLevel = routerResources.get(routerResources.size()-1).getLevel();
// 将不同层级的路由数组对象放到一个map里面
Map<String,List<RouterResource>> levelRoutersMap = new HashMap<>();
for(int i=1;i<maxLevel+1;i++){
levelRoutersMap.put("level"+i,new ArrayList<>());
}
for(RouterResource routerResource : routerResources){
int levelNum = routerResource.getLevel();
levelRoutersMap.get("level"+levelNum).add(routerResource);
}
// 在每一层的下一层节点列表中寻找子节点,避免深度递归
for(int level=1;level<maxLevel;level++){
List<RouterResource> levelRouters = levelRoutersMap.get("level"+level);
List<RouterResource> levelChildrenRouters = levelRoutersMap.get("level"+(level+1));
if(level==1){
for(RouterResource routerResource : levelRouters){
RouterResourceVo routerResourceVo = buildRoleRouteVoByRoleRouter(routerResource);
for(RouterResource childRouter: levelChildrenRouters){
if(childRouter.getPid()== routerResource.getId()){
RouterResourceVo childRouterVo = buildRoleRouteVoByRoleRouter(childRouter);
routerResourceVo.getChildren().add(childRouterVo);
}
}
routerResourceVos.add(routerResourceVo);
}
}else{
for(RouterResource routerResource : levelRouters){
RouterResourceVo routerResourceVo = buildRoleRouteVoByRoleRouter(routerResource);
for(RouterResource childRouter: levelChildrenRouters){
if(childRouter.getPid()== routerResource.getId()){
RouterResourceVo childRouterVo = buildRoleRouteVoByRoleRouter(childRouter);
routerResourceVo.getChildren().add(childRouterVo);
}
}
}
}
}
return routerResourceVos;
}
private RouterResourceVo buildRoleRouteVoByRoleRouter(RouterResource routerResource){
RouterResourceVo routerResourceVo = new RouterResourceVo();
routerResourceVo.setId(routerResource.getId());
routerResourceVo.setName(routerResource.getName());
routerResourceVo.setTitle(routerResource.getTitle());
routerResourceVo.setIcon(routerResource.getIcon());
routerResourceVo.setHidden(routerResource.getHidden()==1);
routerResourceVo.setPath(routerResource.getPath());
routerResourceVo.setComponentUrl(routerResource.getComponentUrl());
routerResourceVo.setLevel(routerResource.getLevel());
routerResourceVo.setKeepAlive(routerResource.getKeepAlive()==1);
return routerResourceVo;
}
}
@RestController
@RequestMapping("/routerResource")
publi c class RouterResourceController {
private static final Logger logger = LoggerFactory.getLogger(RouterResourceController.class);
@Autowired
private RoleRouterService roleRouterService;
/**
* 获取当前角色的路由资源列表
* @param roleId
* @return
*/
@GetMapping("/currentRoleResources")
public RespBean queryCurrentRoleRouters(@RequestParam("roleId") Integer roleId){
logger.info("roleId={}",roleId);
RespBean respBean = new RespBean("success","查询成功");
List<RouterResourceVo> routerResourceVos = roleRouterService.queryRoleRoutersByRoleId(roleId);
respBean.setData(routerResourceVos);
return respBean;
}
}
WebSecurityConfig.java
@Configuration
publi c class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserService userService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/category/all","/reg").authenticated()
.antMatchers("/admin/**").hasRole("superAdmin")///admin/**的URL都需要有超级管理员角色,如果使用.hasAuthority()方法来配置,需要在参数中加上ROLE_,如下.hasAuthority("ROLE_超级管理员")
.anyRequest().authenticated()//其他的路径都是登录后即可访问
.and().formLogin().loginPage("/login_page").successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
// 要修改的代码:把用户信息写入响应体
User user = (User) authentication.getPrincipal();
ObjectMapper objectMapper = new ObjectMapper();
String userInfo = objectMapper.writeValueAsString(user);
out.write("{\"status\":\"success\",\"msg\":\"登录成功\",\"userInfo\":"+userInfo+"}");
out.flush();
out.close();
}
})
.failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
out.write("{\"status\":\"error\",\"msg\":\"登录失败\"}");
out.flush();
out.close();
}
}).loginProcessingUrl("/login") //登录URL
.usernameParameter("username").passwordParameter("password").permitAll()
.and().logout().permitAll().and().csrf().disable().exceptionHandling().accessDeniedHandler(getAccessDeniedHandler());
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/blogimg/**","/index.html","/static/**");
}
@Bean
AccessDeniedHandler getAccessDeniedHandler() {
return new AuthenticationAccessDeniedHandler();
}
}
启动blogserver
服务成功之后即可测试接口
POST http://localhost:8081/login
// form-data
{
"username": "sang",
"password": "123"
}
// 响应信息
{
"status": "success",
"msg": "登录成功",
"userInfo": {
"id": 7,
"username": "sang",
"password": "202cb962ac59075b964b07152d234b70",
"nickname": "江南一点雨",
"enabled": true,
"roles": [
{
"id": 2,
"roleCode": "generalUser",
"roleName": "普通用户"
},
{
"id": 1,
"roleCode": "superAdmin",
"roleName": "超级管理员"
},
{
"id": 5,
"roleCode": "test3",
"roleName": "测试角色3"
}
],
"email": "sang123@qq.com",
"userface": "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1514093920321&di=913e88c23f382933ef430024afd9128a&imgtype=0&src=http%3A%2F%2Fp.3761.com%2Fpic%2F9771429316733.jpg",
"regTime": 1513834229000
}
}
GET http://localhost:8081/routerResource/currentRoleResources?roleId=7
// 响应信息
{
"status": "success",
"msg": "查询成功",
"data": [
{
"id": 1,
"name": "articleManagement",
"title": "文章管理",
"icon": "fa fa-file-text-o",
"hidden": false,
"level": 1,
"path": "/home",
"componentUrl": "@/components/Home",
"keepAlive": false,
"children": [
{
"id": 5,
"name": "articleList",
"title": "文章列表",
"icon": "",
"hidden": false,
"level": 2,
"path": "/articleList",
"componentUrl": "@/components/ArticleList",
"keepAlive": true,
"children": []
},
{
"id": 6,
"name": "publishArticle",
"title": "发表文章",
"icon": "",
"hidden": false,
"level": 2,
"path": "/postArticle",
"componentUrl": "@/components/PostArticle",
"keepAlive": false,
"children": []
},
{
"id": 7,
"name": "blogDetail",
"title": "博客详情",
"icon": "",
"hidden": true,
"level": 2,
"path": "/blogDetail",
"componentUrl": "@/components/BlogDetail",
"keepAlive": false,
"children": []
},
{
"id": 8,
"name": "editBlog",
"title": "编辑博客",
"icon": "",
"hidden": true,
"level": 2,
"path": "/editBlog",
"componentUrl": "@/components/PostArticle",
"keepAlive": false,
"children": []
}
]
},
{
"id": 2,
"name": "userManagement",
"title": "用户管理",
"icon": "fa fa-user-o",
"hidden": false,
"level": 1,
"path": "/home",
"componentUrl": "@/components/Home",
"keepAlive": false,
"children": [
{
"id": 9,
"name": "userManagement",
"title": "用户管理",
"icon": "fa fa-user-o",
"hidden": false,
"level": 2,
"path": "/user",
"componentUrl": "@/components/UserMana",
"keepAlive": false,
"children": []
}
]
},
{
"id": 3,
"name": "categoriesManagement",
"title": "栏目管理",
"icon": "fa fa-reorder",
"hidden": false,
"level": 1,
"path": "/home",
"componentUrl": "@/components/Home",
"keepAlive": false,
"children": [
{
"id": 10,
"name": "cateManagement",
"title": "栏目管理",
"icon": "fa fa-reorder",
"hidden": false,
"level": 2,
"path": "/cateMana",
"componentUrl": "@/components/CateMana",
"keepAlive": false,
"children": []
}
]
},
{
"id": 4,
"name": "dataStatics",
"title": "数据统计",
"icon": "fa fa-bar-chart",
"hidden": false,
"level": 1,
"path": "/home",
"componentUrl": "@/components/Home",
"keepAlive": false,
"children": [
{
"id": 11,
"name": "dataStatics",
"title": "数据统计",
"icon": "fa fa-bar-chart",
"hidden": false,
"level": 2,
"path": "/charts",
"componentUrl": "@/components/DataCharts",
"keepAlive": false,
"children": []
}
]
}
]
}
本文从后端的角度开发了基于用户角色的页面路由权限控制的接口,主要使用了5张表,分别是user表、roles表、roles_user表、router_resources表和role_resource表,roles表作为一个中间表用来关联资源和用户。在这5张表的基础上开发了一个用于前端根据用户角色展示菜单资源用的查询用户角色下的页面菜单资源接口。
用户的认证沿用了bolgserver
项目中的Spring-Security,并在用户认证成功的回调函数中在响应信息中增加写入用户的信息。下一篇文章笔者将结合前端在页面看到基于用户角色控制用户访问菜单权限的效果。接下来几遍文章会写一系列实现从给用户分配角色、给角色授予菜单路由权限到具象到控制按钮操作级别权限的实战文章,敬请期待!
[1] 介绍一个开源博客项目VBlog并打包部署到已存在运行项目的Nginx服务器下
[2] SpringBoot项目集成阿里云对象存储服务实现文件上传
[3] 改造jeecg-boot项目,解决启动报错,跑通开发环境!
本文代码以上到个人的gitee仓库:
https://gitee.com/heshengfu1211/blogserver.git
---END---