上篇日志简单的使用了角色授予和权限授予,接下来,将通过数据库来管理用户对应的权限与角色。

权限表结构设计方式

第一种权限设计模型,权限和角色都考虑。数据库设计中,用户与角色是多对多的关系,角色与权限也是多对多的关系,而权限与资源是一对一的关系。它们的关系如下图所示。

graph LR

用户--关联-->角色--关联-->权限--关联-->资源

第二种权限设计模型,不考虑权限。用户与角色直接对应,是一种多对多的关系,通过不同的角色来对资源进行不同的限制这也是可以的,他们的关系如下所示。

graph LR
用户--关联-->角色

第三种模式权限设计模型,不考虑角色。用户与权限直接对应,也是一种多对多的关系。

graph LR
用户--关联-->权限

当然,或许还有更多的权限表结构方式。

接下来,咱们就使用第一种的方式来体验一把角色授予和权限授予吧。

数据库设计

首先是角色表,角色表的 DDL 如下所示。

create table t_role
(
    id   int auto_increment    primary key,
    name varchar(255) null comment '权限标识'
);

用户表与角色表的关联

create table t_user_role
(
    id     int auto_increment     primary key,
    userId int null comment '用户id',
    roleId int null comment '角色id'
);

权限表的 DDL 如下所示

create table t_pers
(
    id   int auto_increment    primary key,
    name varchar(255) null,
    url  varchar(255) null comment '请求路径'
);

权限表与角色表的关联

create table t_role_perms
(
    id      int auto_increment   primary key,
    roleId  int null,
    permsId int null
);

表数据

角色表 SQL 数据

insert into shiro.t_role (id, name)
values  (1, 'admin'),
        (2, 'user'),
        (3, 'product');

用户——角色表 SQL 关联数据

insert into shiro.t_user_role (id, userId, roleId)
values  (1, 2, 1),
        (2, 3, 3),
        (3, 3, 2);

权限表 SQL 数据

insert into shiro.t_user_role (id, userId, roleId)
values  (1, 2, 1),
        (2, 3, 3),
        (3, 3, 2);

权限——角色表 SQL 关联数据

insert into shiro.t_role_perms (id, roleId, permsId)
values  (1, 1, 1),
        (2, 1, 4),
        (3, 2, 2),
        (4, 3, 3);

权限和角色授予

给用户授予对应的权限和角色,对应 SQL 如下。

SELECT
    t_user.id AS uid,
    t_user.username,
    t_role.id AS rid,
    t_role.`name` AS `rolename`
FROM
    t_user,
    t_role,
    t_user_role
WHERE
    t_user.id = t_user_role.userId
  AND t_user_role.roleId = t_role.id
  AND t_user.username = #{username}

查询该角色对应的权限。

SELECT
    t_pers.*
FROM
    t_role_perms,
    t_pers
WHERE
    t_role_perms.roleId = #{roleId}
  AND t_role_perms.permsId = t_pers.id

查询出来之后,在自定义的 Realm 中,利用 for 循环或者 foreach 方法来授予用户的角色。然后通过每一层循环来给当前的角色授予权限。

User user = userService.findRolesByUsername(username);
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
if(user != null && !CollectionUtils.isEmpty(user.getRoles())) {
    // 角色授予
    user.getRoles().forEach(role -> {
        authorizationInfo.addRole(role.getName());
        // 权限授予
        List<Pers> perms = userService.findPermsByRoleId(role.getId());
        perms.forEach(pers -> {
            System.out.println(pers);
            authorizationInfo.addStringPermission(pers.getName());
        });
    });
    return authorizationInfo;
}

这样一来,权限的授予就保存在数据库中了。当用户访问不同的页面时,就可以控制哪些资源不能访问,哪些资源允许访问。