赞
踩
本文基于web系统的权限控制非常重要的前提下,从ALC和RBAC权限控制两个方面,介绍如何在springboot项目中实现一个完整的权限体系。
源码下载 :https://gitee.com/skyblue0678/springboot-demo
一个后台管理系统,基本都有一套自己的权限体系,权限体系分两种分别是基于控制列表的权限,和基于角色的权限。
基于控制列表的权限,也叫ACL认证体系。就是每个权限,你可以理解为每一个controller方法都有一个自己的用户列表,只有存在于该列表的用户可以访问这个方法。
而基于角色的权限,就是每个用户有自己的角色,而角色拥有多个controller方法的访问权限,用户和角色,角色和接口都是多对多的关系。
ACL: Access Control List
简介:以前非常盛行的一种权限设计,它的核心主要在于用户和权限直接挂钩。
优点:简单易用、开发便捷。
缺点:用户是直接和权限挂钩,导致了在授予权限的时候的复杂性,比较分散,不太易于管理。
例子:常见的文件系统,直接给用户家权限。比如给用户加读写的权限。
RBAC:Role Based Access Control
简介:基于角色的访问控制系统。权限是与角色进行相关联,用户通过成为适当的角色成员从而得到这些角色的权限。
优点:简化了用户和权限的管理,用过对用户进行分类,使得其与角色和权限关联起来。
缺点:开发起来相对于ACL复杂。
例子:基于REAC模型的权限验证框架与应用Apache Shiro、Spring security。
上面说了,ACL是权限和用户直接挂钩,我们需要设计数据库表来存储用户和权限信息。以下是简化的表结构设计:
sql:
- DROP TABLE IF EXISTS `acl`;
- CREATE TABLE `acl` (
- `id` int NOT NULL,
- `user_id` int DEFAULT NULL,
- `permission_id` int DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `user_id` (`user_id`),
- KEY `permission_id` (`permission_id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-
- DROP TABLE IF EXISTS `permission`;
- CREATE TABLE `permission` (
- `id` int NOT NULL AUTO_INCREMENT,
- `permission` varchar(50) DEFAULT NULL,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-
- DROP TABLE IF EXISTS `user`;
- CREATE TABLE `user` (
- `id` int NOT NULL AUTO_INCREMENT,
- `username` varchar(50) DEFAULT NULL,
- `password` varchar(50) DEFAULT NULL,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
初始化数据:
- -- 插入用户数据
- INSERT INTO User (id, username, password) VALUES (1, 'jack', '1');
- INSERT INTO User (id, username, password) VALUES (2, 'rose', '1');
-
- -- 插入权限数据
- INSERT INTO Permission (id, permission) VALUES (1, 'device:list');
- INSERT INTO Permission (id, permission) VALUES (2, 'device:add');
-
-
- -- 插入ACL数据
- INSERT INTO ACL (id, user_id, permission_id) VALUES (1, 1, 1);
- INSERT INTO ACL (id, user_id, permission_id) VALUES (2, 2, 2);
有了用户,权限,acl三张表后,就根据matisplus将对应的增删改查功能实现。
Mapper
- public interface UserMapper extends BaseMapper<User> {
- }
-
- public interface PermissionMapper extends BaseMapper<Permission> {
- }
-
- public interface AclMapper extends BaseMapper<Acl> {
- }
Service
- public interface UserService extends IService<User> {
- User getByUsername(String username);
- }
-
-
- public interface PermissionService extends IService<Permission> {
- List<Permission> findByIds(Set<Integer> permIds);
- }
-
- public interface AclService extends IService<Acl> {
-
- List<Permission> findByUserId(Integer id);
- }
-
impl
- @Service
- @Slf4j
- public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
-
- @Override
- public User getByUsername(String username) {
- return baseMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUserName,username));
- }
- }
-
-
- @Service
- @Slf4j
- public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements PermissionService {
- @Override
- public List<Permission> findByIds(Set<Integer> permIds) {
- return baseMapper.selectBatchIds(permIds);
- }
- }
-
- @Service
- @Slf4j
- public class AclServiceImpl extends ServiceImpl<AclMapper, Acl> implements AclService {
-
- @Resource
- PermissionService permissionService;
-
- @Override
- public List<Permission> findByUserId(Integer id) {
- List<Acl> acls = baseMapper.selectList(new LambdaQueryWrapper<Acl>().eq(Acl::getUserId, id));
- Set<Integer> permIds = acls.stream().map(Acl::getPermissionId).collect(Collectors.toSet());
- return permissionService.findByIds(permIds);
- }
- }
最后是在login里面获取用户的权限
- @GetMapping("/acl/login")
- public String loginAcl(String username,String password){
- User user = userService.getByUsername(username);
- if(Objects.nonNull(user)){
- if(!user.getPwd().equals(password)){
- return "密码错误!";
- }
- //根据用户获取ACL权限列表
- List<Permission> permissionList = aclService.findByUserId(user.getId());
- return permissionList.toString();
- }else {
- return "用户名不存在";
- }
- }
测试:
浏览器访问: http://localhost:8080/acl/login?username=jack&password=1
[Permission(id=1, permission=device:list)]
这个例子中,我们通过用户登录,获取了对应的权限列表,后续的章节中,我们会做真实的权限校验。
RBAC比ACL就是多了一个角色的概念,用户是拥有角色的,角色对应具体的权限,所以控制起来更加的灵活。
以下是简化的表结构设计:
sql
- DROP TABLE IF EXISTS `role`;
- CREATE TABLE `role` (
- `id` int NOT NULL AUTO_INCREMENT,
- `role_name` varchar(20) DEFAULT NULL,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-
- INSERT INTO `role` VALUES ('1', '设备管理员');
-
- DROP TABLE IF EXISTS `role_permission`;
- CREATE TABLE `role_permission` (
- `id` int NOT NULL AUTO_INCREMENT,
- `role_id` int DEFAULT NULL,
- `permission_id` int DEFAULT NULL,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-
- INSERT INTO `role_permission` VALUES ('1', '1', '1');
-
- DROP TABLE IF EXISTS `user_role`;
- CREATE TABLE `user_role` (
- `id` int NOT NULL AUTO_INCREMENT,
- `user_id` int DEFAULT NULL,
- `role_id` int DEFAULT NULL,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-
- INSERT INTO `user_role` VALUES ('1', '1', '1');
-
RBAC的登录方法
- @GetMapping("/rbac/login")
- public String loginRbac(String username,String password){
- User user = userService.getByUsername(username);
- if(Objects.nonNull(user)){
- if(!user.getPwd().equals(password)){
- return "密码错误!";
- }
- //根据用户获取ACL权限列表
- List<Permission> permissionList = userService.findByUserRole(user.getId());
- return permissionList.toString();
- }else {
- return "用户名不存在";
- }
- }
根据用户角色查询权限
- @Override
- public List<Permission> findByUserRole(Integer id) {
- return baseMapper.findByUserRole(id);
- }
mapper
- public interface UserMapper extends BaseMapper<User> {
- List<Permission> findByUserRole(@Param("id") Integer id);
- }
-
xml:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- <mapper namespace="com.it.demo.mapper.UserMapper">
-
-
- <select id="findByUserRole" resultType="com.it.demo.entity.Permission">
- SELECT
- e.*
- FROM
- USER a
- LEFT JOIN user_role b ON a.id = b.user_id
- LEFT JOIN role c ON b.role_id = c.id
- LEFT JOIN role_permission d ON c.id = d.role_id
- LEFT JOIN permission e ON d.permission_id = e.id
- WHERE
- a.id = #{id}
- </select>
- </mapper>
-
访问:http://localhost:8080/rbac/login?username=jack&password=1
[Permission(id=1, permission=device:list)]
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。