一、 什么是 RBAC
RBAC(Role-Based Access Control )基于角色的访问控制。
RBAC 认为权限的过程可以抽象概括为:
判断【Who 是否可以对 What 进行 How 的访问操作(Operator)】
- Who:权限的拥用者或主体
- What:权限针对的对象或资源
- How:具体的权限
- Operator:操作。表明对 What 的 How 操作。也就是 Privilege+Resource
- Role:角色,一定数量的权限的集合。权限分配的单位与载体,目的是隔离User与Privilege的逻辑关系
用户角色 权限控制模型
二、 RBAC96 模型
1 RBAC 模型
RBAC96 模型家族,其中包括了 RBAC0~RBAC3 四个概念模型。
2 RBAC0
定义了能构成一个 RBAC 控制系统的最小的元素集合在 RBAC 之中,包含用户 users(USERS)、角色 roles(ROLES)、目标 objects(OBS)、操作operations(OPS)、许可权 permissions(PRMS)五个基本数据元素,权限被赋予角色,而不是用户,当一个角色被指定给一个用户时,此用户就拥有了该角色所包含的权限。会话 sessions是用户与激活的角色集合之间的映射。RBAC0 与传统访问控制的差别在于增加一层间接性带来了灵活性,RBAC1、 RBAC2、RBAC3 都是先后在 RBAC0 上的扩展。
UA(User Assignment):用户角色分配
PA(Permission Assignment):角色许可分配
3 RBAC1
引入角色间的继承关系
角色间的继承关系可分为一般继承关系和受限继承关系。一般继承关系仅要求角色继承关系是一个绝对偏序关系,允许角色间的多继承。而受限继承关系则进一步要求角色继承关系是一个树结构。
4 RBAC2
该模型中添加了责任分离关系
RBAC2 的约束规定了权限被赋予角色时,或角色被赋予用户时,以及当用户在某一时刻激活一个角色时所应遵循的强制性规则。责任分离包括静态责任分离和动态责任分离。约束与用户-角色-权限关系一起决定了 RBAC2 模型中用户的访问许可。
5 RBAC3
RBAC3 包含了 RBAC1 和 RBAC2
既提供了角色间的继承关系,又提供了责任分离关系
三、 RBAC 实战
1 需求
- 1)实现用户登录功能
- 2)使用 RBAC0 模型管理系统权限
- 3)对系统的菜单以及菜单中的链接进行管理。
- 4)用户登录后首页根据用户角色显示该角色所对应的菜单
- 5)禁止用户越级访问
2 技术选择
- 1)框架:SpringMVC+Spring+Mybatis
- 2)数据库:Mysql
3 数据库设计
4 创建表
4.1创建用户表
CREATE TABLE `users` (
`username` varchar(50) NOT NULL,
`userpwd` varchar(50) DEFAULT NULL,
`role_id` int(11) DEFAULT NULL,
PRIMARY KEY (`username`),
KEY `users_fk` (`role_id`),
CONSTRAINT `users_fk` FOREIGN KEY (`role_id`) REFERENCES `roles` (`roleid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
4.2创建角色表
CREATE TABLE `roles` (
`roleid` int(11) NOT NULL AUTO_INCREMENT,
`rolename` varchar(50) DEFAULT NULL,
PRIMARY KEY (`roleid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
4.3创建菜单表
CREATE TABLE `menus` (
`menuid` int(11) NOT NULL AUTO_INCREMENT,
`menuname` varchar(50) DEFAULT NULL,
`menuurl` varchar(50) DEFAULT NULL,
`fatherid` int(11) DEFAULT NULL,
PRIMARY KEY (`menuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
4.4创建功能表
CREATE TABLE `funs` (
`funid` int(11) NOT NULL AUTO_INCREMENT,
`funname` varchar(50) DEFAULT NULL,
`funurl` varchar(50) DEFAULT NULL,
`menu_id` int(11) DEFAULT NULL,
PRIMARY KEY (`funid`),
KEY `menus_fk` (`menu_id`),
CONSTRAINT `menus_fk` FOREIGN KEY (`menu_id`) REFERENCES `menus`
(`menuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
4.5创建菜单角色中间表
CREATE TABLE `roles_menus` (
`roles_id` int(11) NOT NULL,
`menus_id` int(11) NOT NULL,
PRIMARY KEY (`roles_id`,`menus_id`),
KEY `roles_menus_fk2` (`menus_id`),
CONSTRAINT `roles_menus_fk1` FOREIGN KEY (`roles_id`) REFERENCES `roles`
(`roleid`),
CONSTRAINT `roles_menus_fk2` FOREIGN KEY (`menus_id`) REFERENCES `menus`
(`menuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
5 编写用户登录 Controller
5.1创建login.jsp
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'login.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <h3><font color="red">${requestScope.msg}</font></h3> <form action="userLogin" method="post"> 用户名<input type="text" name="username"><br> 密码<input type="password" name="userpwd"><br> <input type="submit" value="提交"><br> </form> </body> </html>
5.2创建 LoginController
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package com.controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import com.exception.UsersException; import com.pojo.Users; import com.service.UserService; @Controller public class LoginController { @Autowired private UserService userService; @RequestMapping("/userLogin") public String userLogin(Users users,Model model,HttpServletRequest request){ try{ Users u=this.userService.userLongin(users.getUsername(), users.getUserpwd()); HttpSession session = request.getSession(); session.setAttribute("user", u); }catch(UsersException e){ e.printStackTrace(); model.addAttribute("msg", e.getMessage()); return "/login"; } return "redirect:/index"; } }
6 页面布局
6.1 index.jsp
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <frameset rows="15%,*,10%" border="1"> <frame src="head" scrolling="auto" name="head"> <frameset cols="20%"> <frame src="menu" scrolling="auto" name="menu"> <frame src="body" scrolling="auto" name="body"> </frameset> <frame src="foot" scrolling="auto" name="foot"> </frameset> </html>