1

前言

image.png

前面一讲中,主要是针对于简单角色,权限规则基本不变的情况。我们通过写代码将其基本权限控制写到代码中去。

在一个内管系统中,角色众多,权限复杂,权限规则随着公司和业务的发展不断变化。还有菜单控制给用户是否查看,能否访问。 这个时候,这样的场景我们是不能去写代码的。人员都会时常变得,我们需要把这些数据存储到数据库中。

内容

1.RBAC数据模型

表结构:牵涉到5张表,3张主表,2张关系表。
5张表中有4张是业务人员维护的,其中有一张表是开发人员维护的(资源表) image.png

2.开发

新建模块spring-security-authorize工程,这个工程里面实现的rbac,提供基本的增删查改和controller接口。
我们需要知道的是spring-security-authorize跟spring-security没有关系的,他只是我们根据我们业务需求开发的数据表上的增删改查。跟Spring-security有关系的是啥?你的安全模块最终要控制的是这些url能不能访问?有关系的是这些url。url能不能访问。用户能不能访问此url。

用户最终的url是存储到我们的资源表的,那这些url如何跟我们的spring-security怎样关联起来呢?

我们要实现我们自己写的权限模块和spring-security对接起来。对接的话,我们需要做一些配置。我们需要在自己的模块做一些配置?也需要在Spring-Security模块做一些配置。

2.1 spring-security-authorize模块

我们在spring-security-authorize模块pom.xml文件中添加依赖:

public interface RbacService {
    /**
     * 判断是否能够访问
     * @param request  用户请求
     * @param authentication  用户信息
     * @return
     */
    boolean hasPermission(HttpServletRequest request, Authentication authentication);
}

创建实现类:

@Component("rbacService")
public class RbacServiceImpl implements RbacService {

    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        Object principal = authentication.getPrincipal();
        boolean hasPermission = false;
        if (principal instanceof UserDetails){
            //获取用户名
            String username = ((UserDetails) principal).getUsername();

            //拿到用户名之后,我们可以根据RBAC的数据结构,去查找用户名对应用户角色
            //然后根据用户角色查询用户菜单和按钮,最终拿到所有的url
            Set<String> urls = new HashSet<>();//简单起见,我们这里创建url,实际上需要根据数据库查询

            for (String url:urls) {
                //由于用户访问的请求可能有"/user/*" 也有"/user/1",这种请求,所以我们不能用equals比较,需要用AntPathMatcher
                 if(antPathMatcher.match(url,request.getRequestURI())){
                    hasPermission = true;
                    break;
                 }
            }

        }
        return hasPermission;
}

2.2 spring-security-core模块

我们在spring-security里面需要做的是:我们需要写一个权限表达式去调用上面写的RbacService的hasPermission方法。最终spring-security看能不能过,最终都是一个权限表达式。

我们在spring-security里面配置:

image.png

由此我们产生了2个问题:

2.2.1 问题1

我们在上面spring-security-demo的Provider里面配置了anyRequest(),说明任何请求都需要走这个规则,但是我们在之前spring-security-core的Manager里面也已经写过了:

image.png

因为MyAuthorizeConfigManager是在最后调用的,所以MyAuthorizeConfigManager的配置会覆盖掉: DemoAuthorizeConfigProvider,我们我们先注释

image.png

2.2.1 问题2

因为我们的anyRequest()是这对于所有请求的。
那么下面的配置一定要在最后生效。

image.png

如果我们一上来就读取上面配置,那么所有请求都走上面配置的话就会有问题,因为我们安全模块里面登录授权部分请求是需要permitAll();

image.png

所以要求我们读取顺序是有要求的:
我们要求我们的安全模块先读取,然后再读取授权模块的request。
我们需要使用注解:@Order

image.png

image.png
因为DemoAuthorizeConfigProvider里面是最大值,所以是最后读取出来的。

以上加载Provider是有顺序的,所以我们的Manager里面是一个有序的集合:List

image.png

然后我们在spring-security-demo项目的pom.xml文件添加:spring-security-authorize依赖。
image.png


startshineye
94 声望26 粉丝

我在规定的时间内,做到了我计划的事情;我自己也变得自信了,对于外界的人跟困难也更加从容了,我已经很强大了。可是如果我在规定时间内,我只有3分钟热度,哎,我不行,我就放弃了,那么这个就是我自己的问题,因为你自己...


引用和评论

0 条评论