SpringSecurity 细粒度权限控制
一、Role 和 Authority的区别
角色用来表示某一类权限的集合,权限粒度更小,方便细粒度控制
二、创建用户、角色、权限相关表:
CREATE TABLE `common_user` (`id` bigint(20) NOT NULL COMMENT '主键id',`login_name` varchar(32) CHARACTER SET utf8 NOT NULL COMMENT '登录名称',`password` varchar(2048) CHARACTER SET utf8 NOT NULL COMMENT '密码',`status` varchar(10) CHARACTER SET utf8 DEFAULT NULL COMMENT '认证状态:SUCCESS-认证通过;FAILED-认证失败;INIT-初始化;LOCKED-锁定;UNLOCKED-自动解锁',`phone` varchar(13) CHARACTER SET utf8 DEFAULT NULL COMMENT '手机号',`born` date DEFAULT NULL COMMENT '出生日期',`fail_count` int(2) DEFAULT NULL COMMENT '失败次数',`creator` varchar(20) CHARACTER SET utf8 NOT NULL COMMENT '创建人',`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',`modifier` varchar(20) CHARACTER SET utf8 DEFAULT NULL COMMENT '修改人',`modify_time` timestamp NULL DEFAULT NULL COMMENT '修改时间',PRIMARY KEY (`id`) USING BTREE,UNIQUE KEY `uk_login_name` (`login_name`) USING BTREE COMMENT 'login_name唯一索引',KEY `idx_phone` (`phone`) USING BTREE COMMENT 'phone索引'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';CREATE TABLE `common_user_role` (`id` bigint(20) NOT NULL COMMENT '主键id',`user_id` bigint(20) NOT NULL COMMENT '用户id',`role_id` bigint(20) NOT NULL COMMENT '角色id',`creator` varchar(20) NOT NULL COMMENT '创建人',`create_time` datetime NOT NULL COMMENT '创建时间',`modifier` varchar(20) DEFAULT NULL COMMENT '修改人',`modify_time` datetime DEFAULT NULL COMMENT '修改时间',PRIMARY KEY (`id`) USING BTREE,KEY `idx_user_role` (`user_id`,`role_id`) USING BTREE COMMENT '用户角色组合索引'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户角色表';CREATE TABLE `common_role` (`id` bigint(20) NOT NULL COMMENT '主键id',`name` varchar(32) NOT NULL COMMENT '角色名称',`desc` varchar(64) DEFAULT NULL COMMENT '角色描述',`creator` varchar(20) NOT NULL COMMENT '创建人',`create_time` datetime NOT NULL COMMENT '创建时间',`modifier` varchar(20) DEFAULT NULL COMMENT '修改人',`modify_time` datetime DEFAULT NULL COMMENT '修改时间',PRIMARY KEY (`id`) USING BTREE,KEY `idx_name` (`name`) USING BTREE COMMENT '角色名称索引'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表';CREATE TABLE `common_role_permission` (`id` bigint(20) NOT NULL COMMENT '主键id',`role_id` bigint(20) NOT NULL COMMENT '角色id',`permission_id` bigint(20) NOT NULL COMMENT '权限id',`creator` varchar(20) NOT NULL COMMENT '创建人',`create_time` datetime NOT NULL COMMENT '创建时间',`modifier` varchar(20) DEFAULT NULL COMMENT '修改人',`modify_time` datetime DEFAULT NULL COMMENT '修改时间',PRIMARY KEY (`id`) USING BTREE,KEY `idx_role_permission` (`role_id`,`permission_id`) USING BTREE COMMENT '角色权限组合索引'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色权限表';CREATE TABLE `common_role` (`id` bigint(20) NOT NULL COMMENT '主键id',`name` varchar(32) NOT NULL COMMENT '角色名称',`desc` varchar(64) DEFAULT NULL COMMENT '角色描述',`creator` varchar(20) NOT NULL COMMENT '创建人',`create_time` datetime NOT NULL COMMENT '创建时间',`modifier` varchar(20) DEFAULT NULL COMMENT '修改人',`modify_time` datetime DEFAULT NULL COMMENT '修改时间',PRIMARY KEY (`id`) USING BTREE,KEY `idx_name` (`name`) USING BTREE COMMENT '角色名称索引'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表';
三、给资源授予权限(角色或权限)
注意:角色 (“ADMIN”,“MEMBER”,“GUEST”),在SpringSecurity中设置时需要添加前缀ROLE_,所以这里存储有2种方案
第一种:数据库存储角色名称,没有ROLE_的前缀,如下图
那么,在角色加载的时候,需要补上前缀ROLE_
接口配置角色访问策略时,无需添加ROLE_前缀了,SpringSecurity在进行角色权限判断时会自动加ROLE_前缀,这样配置:
配置后,当前用户如果登录成功,便有了该接口的访问权限(需要行政区划平铺数据的私信):
第二种:数据库存储角色的时候就添加ROLE_前缀,这样在角色加载时就无需再添加ROLE_前缀了,不再赘述
三、角色与权限结合起来控制接口的访问权限
例如:角色ROLE必须是MEMBER
,并且有权限division:flat_cities
才能访问该接口,接口处这样配置:
当前用户已设置MEMBER
角色和division:flat_cities
权限,访问试试:
此时,出了点小插曲,登录失效了,这里就是SpringSecurity+RSA+JWT+Redis的权限控制和登录退出控制
通过接口先登录,获取Token,登录成功后响应的header返回了X-Auth-Token令牌,每次请求携带该令牌即可访问接口,仅仅是允许访问,不代表有权限,权限还是通过角色+权限来控制的
接下来访问接口:
如果:把当前用户的角色保留,权限去掉division:flat_cities
,会怎样?我这里将权限改错等同于去掉了,因为接口配置的权限是division:flat_cities
再次携带当前登录用户的Token访问接口,发现就无权访问了:
二、细粒度的资源控制
authenticated():通过认证的用户都可以访问
permitAll():允许所有人访问,即使未登录
authorizeRequests():更细粒度的控制
access(String): SpEL:Spring表达式
.access(“hasRole(‘大师’) AND hasAuthority(‘user:delete’) OR hasIpAddress(‘192.168.0.1’)”)
四、细粒度的资源控制必要的注解
- 开启注解控制权限模式
@EnableWebSecurity:开启 Spring Security 注解
@EnableGlobalMethodSecurity(prePostEnabled=true):开启全局的细粒度方法级别权限控制功能
几个权限检查注解
@PreAuthorize:方法执行前检查
@PreAuthorize(“hasRole(‘ADMIN’)”)
@PostAuthorize:方法执行后检查,失败抛异常
@PostAuthorize:允许方法调用,但是,如果表达式结果为false抛出异常
@PostAuthorize("returnObject.user.usernameprincipal.username")
@PostFilter:允许方法调用,但是按照表达式过滤方法结果
@PostFilter("returnObject.user.sex’男’ ")
@PreFilter:允许方法调用,但必须在进入方法前过滤输入值
@Secured:拥有指定角色才可以访问方法
@Secured(‘ADMIN’) 等价于 @PreAuthorize(“hasRole(‘ADMIN’)”)
五、细粒度的资源控制注解中可写的表达式
所有能使用的表达式见下面文档连接:
https://docs.spring.io/spring-security/site/docs/4.0.1.RELEASE/reference/htmlsingle/#el-common-built-in