项目gitee地址:https://gitee.com/kaidilake118/springsecurity
项目结构说明
SQL脚本
/*
Navicat MySQL Data Transfer
Source Server : mysqldb
Source Server Version : 50562
Source Host : localhost:3308
Source Database : acldb
Target Server Type : MYSQL
Target Server Version : 50562
File Encoding : 65001
Date: 2020-10-29 14:36:58
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for acl_permission
-- ----------------------------
DROP TABLE IF EXISTS `acl_permission`;
CREATE TABLE `acl_permission` (
`id` char(19) NOT NULL DEFAULT '' COMMENT '编号',
`pid` char(19) NOT NULL DEFAULT '' COMMENT '所属上级',
`name` varchar(20) NOT NULL DEFAULT '' COMMENT '名称',
`type` tinyint(3) NOT NULL DEFAULT '0' COMMENT '类型(1:菜单,2:按钮)',
`permission_value` varchar(50) DEFAULT NULL COMMENT '权限值',
`path` varchar(100) DEFAULT NULL COMMENT '访问路径',
`component` varchar(100) DEFAULT NULL COMMENT '组件路径',
`icon` varchar(50) DEFAULT NULL COMMENT '图标',
`status` tinyint(4) DEFAULT NULL COMMENT '状态(0:禁止,1:正常)',
`is_deleted` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '逻辑删除 1(true)已删除, 0(false)未删除',
`gmt_create` datetime DEFAULT NULL COMMENT '创建时间',
`gmt_modified` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_pid` (`pid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限';
-- ----------------------------
-- Records of acl_permission
-- ----------------------------
INSERT INTO `acl_permission` VALUES ('1', '', '系统日志查看', '0', 'sys:log', '/sys/log', null, null, null, '0', '2020-10-28 16:36:42', '2020-10-28 16:36:39');
INSERT INTO `acl_permission` VALUES ('2', '', '会员信息查看', '0', 'sys:member', '/sys/member', null, null, null, '0', null, null);
INSERT INTO `acl_permission` VALUES ('3', '', '接口限流', '0', 'sys:limit', '/sys/limit', null, null, null, '0', null, null);
INSERT INTO `acl_permission` VALUES ('4', '', '应用部署', '0', 'sys:deploy', '/sys/deploy', null, null, null, '0', null, null);
-- ----------------------------
-- Table structure for acl_role
-- ----------------------------
DROP TABLE IF EXISTS `acl_role`;
CREATE TABLE `acl_role` (
`id` char(19) NOT NULL DEFAULT '' COMMENT '角色id',
`role_name` varchar(20) NOT NULL DEFAULT '' COMMENT '角色名称',
`role_code` varchar(20) DEFAULT NULL COMMENT '角色编码',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`is_deleted` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '逻辑删除 1(true)已删除, 0(false)未删除',
`gmt_create` datetime NOT NULL COMMENT '创建时间',
`gmt_modified` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of acl_role
-- ----------------------------
INSERT INTO `acl_role` VALUES ('1', '超级管理员', 'admin', null, '0', '2019-11-11 13:09:32', '2019-11-18 10:27:18');
INSERT INTO `acl_role` VALUES ('2', '普通管理员', 'user', null, '0', '2019-11-11 13:09:45', '2019-11-18 10:25:44');
-- ----------------------------
-- Table structure for acl_role_permission
-- ----------------------------
DROP TABLE IF EXISTS `acl_role_permission`;
CREATE TABLE `acl_role_permission` (
`id` char(19) NOT NULL DEFAULT '',
`role_id` char(19) NOT NULL DEFAULT '',
`permission_id` char(19) NOT NULL DEFAULT '',
`is_deleted` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '逻辑删除 1(true)已删除, 0(false)未删除',
`gmt_create` datetime NOT NULL COMMENT '创建时间',
`gmt_modified` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_role_id` (`role_id`),
KEY `idx_permission_id` (`permission_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色权限';
-- ----------------------------
-- Records of acl_role_permission
-- ----------------------------
INSERT INTO `acl_role_permission` VALUES ('1', '1', '1', '0', '2020-10-28 16:40:06', '2020-10-28 16:40:08');
INSERT INTO `acl_role_permission` VALUES ('2', '1', '3', '0', '2020-10-28 16:40:17', '2020-10-28 16:40:20');
INSERT INTO `acl_role_permission` VALUES ('3', '1', '4', '0', '2020-10-28 16:40:59', '2020-10-28 16:41:02');
INSERT INTO `acl_role_permission` VALUES ('4', '2', '2', '0', '2020-10-28 16:41:14', '2020-10-28 16:41:16');
-- ----------------------------
-- Table structure for acl_user
-- ----------------------------
DROP TABLE IF EXISTS `acl_user`;
CREATE TABLE `acl_user` (
`id` char(19) NOT NULL COMMENT '会员id',
`username` varchar(20) NOT NULL DEFAULT '' COMMENT '微信openid',
`password` varchar(255) NOT NULL DEFAULT '' COMMENT '密码',
`nick_name` varchar(50) DEFAULT NULL COMMENT '昵称',
`salt` varchar(255) DEFAULT NULL COMMENT '用户头像',
`token` varchar(100) DEFAULT NULL COMMENT '用户签名',
`is_deleted` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '逻辑删除 1(true)已删除, 0(false)未删除',
`gmt_create` datetime NOT NULL COMMENT '创建时间',
`gmt_modified` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
-- ----------------------------
-- Records of acl_user
-- ----------------------------
INSERT INTO `acl_user` VALUES ('1', 'admin', '$2a$10$9F24lA5HYRVzM7p1af3ZeuhJcarCLZhF2KFkZPssYlkc5h9M1ml3m', 'admin', '', null, '0', '2019-11-01 10:39:47', '2019-11-01 10:39:47');
INSERT INTO `acl_user` VALUES ('2', 'test', '$2a$10$mUz1L.UXH9j98TymD0FXy.m5G.xo7U69j3zkv4KDUtcxyiLWN3LKC', 'test', null, null, '0', '2019-11-01 16:36:07', '2019-11-01 16:40:08');
-- ----------------------------
-- Table structure for acl_user_role
-- ----------------------------
DROP TABLE IF EXISTS `acl_user_role`;
CREATE TABLE `acl_user_role` (
`id` char(19) NOT NULL DEFAULT '' COMMENT '主键id',
`role_id` char(19) NOT NULL DEFAULT '0' COMMENT '角色id',
`user_id` char(19) NOT NULL DEFAULT '0' COMMENT '用户id',
`is_deleted` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '逻辑删除 1(true)已删除, 0(false)未删除',
`gmt_create` datetime NOT NULL COMMENT '创建时间',
`gmt_modified` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_role_id` (`role_id`),
KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of acl_user_role
-- ----------------------------
INSERT INTO `acl_user_role` VALUES ('1', '1', '1', '0', '2020-10-28 16:35:05', '2020-10-28 16:35:08');
INSERT INTO `acl_user_role` VALUES ('2', '2', '1', '0', '2020-10-28 16:35:21', '2020-10-28 16:35:24');
INSERT INTO `acl_user_role` VALUES ('3', '2', '2', '0', '2020-10-28 16:35:37', '2020-10-28 16:35:40');
WebSecurityConfig配置类说明
这个类的核心方法如下
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.formLogin()
//自定义登录页面
.loginPage("/login.html")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/index.html")
.and()
.authorizeRequests()
//一定要开放登录的相关接口,否则会无限重定向
.antMatchers("/login.html", "/login").permitAll()
// .antMatchers("/sys/log","/sys/limit","/sys/deploy").hasRole("admin")
// .antMatchers("/sys/member").hasRole("user")
.antMatchers("/index.html").authenticated();
//使用自定义的鉴权方式
//.anyRequest().access("@rbacService.hasPermission(request,authentication)");
//其他的请求认证后即可访问
//.anyRequest().authenticated();
}
其中通过这个方法我们可以指定登录页面,登录请求,以及登录后的默认跳转地址,这些都是url来指定的,我们也可以自己指定登录成功或失败以后的handler,来自己写处理逻辑。
注意这里:
anyRequest().access("@rbacService.hasPermission(request,authentication)");
@rbacService表示容器中的一个组件,我们调用这个组件的hasPermission方法将请求对象和认证主体传入,参数名是固定的。
我们来看以下rbacService这个类里面的逻辑。
RBACService
@Service("rbacService")
public class MyRBACService {
/**
* 这个方法是我们自定义的鉴权方法,(根据url进行鉴权)那就是看当前认证的这个用户权限集合中有没有当前访问的
* 请求url
* @param request
* @param authentication
* @return
*/
public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
Object principal = authentication.getPrincipal();
if (principal instanceof UserDetails) {
User user = (User) authentication.getPrincipal();
Collection<GrantedAuthority> authorities = user.getAuthorities();
//获取请求Uri
String requestURI = request.getRequestURI();
if (!authorities.isEmpty()){
for (GrantedAuthority authority : authorities) {
String auth = authority.getAuthority();
if (auth.equals(requestURI)){
return true;
}
}
}
}
return false;
}
}
我们看一下数据库中的权限实体类的字段,注意有permission_value和path这两个字段,我们在为用户授权的时候是将这两个字段的值都作为权限授权给用户的,也就是如果用户有id为1的这个权限,则我们的userDetailSerivce中实际上是给他了sys:log和/sys/log这两个权限。其中path就对应了我们controller中的资源路径,而permission_value就可以结合Security的注解@PreAuthorize(“hasAnyAuthority(‘sys:log’)”)来使用,这样做的好处就是我们即可以通过请求路径来判断,也可以通过权限表示来判断。
详细源码可下载gitee上的项目地址 https://gitee.com/kaidilake118/springsecurity