上一篇文章只是实现了 UserDetailService 接口,简单new 了一个 User,并没有连接数据库来验证用户信息和权限。本篇将详细介绍连接数据库之后的认证操作。
RBAC权限控制,涉及到用户(User)、角色(Role)和权限(Permission)三个实体,这三个实体是相互独立的,直到将用户关联上了角色,将角色关联上了权限,形成Role_User和Role_Permission 的关系。对应到数据库表上,则需要建立相应的5张数据表。我的例子中的表结构如下所示:
用户表:
CREATE TABLE `operation_user` (
`user_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户 id',
`user_name` varchar(45) NOT NULL COMMENT '用户姓名',
`pwd` varchar(50) NOT NULL COMMENT '密码',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
角色表:
CREATE TABLE `role` (
`role_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '角色 id',
`role_name` varchar(45) NOT NULL COMMENT '角色名称',
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
权限表:
CREATE TABLE `permission` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '权限 id',
`name` varchar(45) DEFAULT NULL COMMENT '权限名称',
`description` varchar(45) DEFAULT NULL COMMENT '权限描述',
`url` varchar(45) DEFAULT NULL COMMENT '资源 url',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
用户-角色关系表:
CREATE TABLE `role_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL COMMENT '用户 id',
`role_id` int(11) NOT NULL COMMENT '角色 id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4
角色-权限关系表:
CREATE TABLE `role_permission` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`role_id` int(11) NOT NULL COMMENT '角色 id',
`perm_id` int(11) NOT NULL COMMENT '权限 id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4
以上是表结构。
以下是 spring security 工作机制大致示意图,便于在整体上有个概念。https://www.processon.com/view/5a0551c2e4b06bed41ceef0e
根据以上流程示意图,需要实现以下类:
(1)——(5)参考资源:http://blog.****.net/code__code/article/details/53885510,http://blog.****.net/u012373815/article/details/54633046
(1)MySecurityFilter,继承AbstractSecurityInterceptor,实现Filter接口。功能:拦截登录之后的 url,实际上登录的 url 也拦截了(从我的这个例子来看),注入MyAccessDecisionManager的 bean。
(2)MyInvocationSecurityMetadataSourceService ,功能:加载所有权限,判断某个 url 是否在权限表中,如果在的话则判断该用户是否有权限访问,要调用MyAccessDecisionManager类中的decide 方法。
(3)MyAccessDecisionManager,功能:判断用户是否有权限访问。
(4)MyUserDetailServiceImpl实现UserDetailsService接口,重写loadUserByUsername方法,功能:从数据库里查询是否存在该用户,判断密码是否一致,读取该用户权限。
(5)SecurityConfig,继承WebSecurityConfigurerAdapter,功能:注入(1)(4)(6)的bean,配置 HttpSecurity资源访问规则。
(6)MyAccessDeniedHandler实现AccessDeniedHandler接口,重写 handle 方法,功能:返回自定义的403页面。
参考资源:http://blog.****.net/jiangshanwe/article/details/73234988,http://dianfusoft.iteye.com/blog/2008721
因为代码比较多,我就直接把项目完整代码放到 git (https://github.com/weichaolei/springboot-spring-security)上。供大家参考,写的不妥之处,欢迎大家批评指正。