springboot整合springsecurity安全框架(后端spring_security模块代码可直接使用,根据需求自定义修改)
SpringSecurity简介
最下面有与springboot整合的模块代码
用户认证和用户授权
- 主要包含两部分:用户认证和用户授权
- 用户认证:进入用户登录时候,输入用户名密码,查询数据库查看是否正确,如果正确,则认证成功
- 用户授权:登陆了系统,登录用户可能是不同的角色,比如普通用户和管理员
- springsecurity本质上就是用filter对请求的路径进行过滤
- 如果是基于Session,则会对cookie里的sessionId进行解析,找到服务器存储的session信息,然后判断用户是否符合请求的要求
- 如果是token,则解析出token,然后将当前请求加入到springsecurity管理的权限信息中去
认证与授权实现思路
如果系统的模块众多,每个模块都需要进行授权与认证,所以选用token的形式进行授权与认证比较方便,用户根据用户名密码认证成功,然后返回当前用户角色的一系列权限值,并以用户名为key,权限列表为value存入redis中,根据用户相关信息返回token,浏览器将token记录到cookie中,每次调用接口都默认将token携带到header请求头中,springsecurity会解析header头获取token信息,解析token获取当前用户名,根据用户名就能够从中获取权限列表,这样就能够完成权限控制
同类型产品对比
SpringSecurity特点:
- 和Spring无缝整合
- 全面的权限控制
- 转为web开发而设计
- 旧版不能脱离web环境使用
- 新版对整个框架进行了分层抽离,分成了核心模块和web模块。单独引入核心模块则能脱离web环境
- 重量级
shiro特点:
- 轻量级,shiro主张把复杂的简单化。针对性能要求高的互联网应用有更好表现
- 通用性
- 好处:不局限于web环境
- 缺陷:在web环境下一些特定需求需要手动编写代码控制
模块划分
基本原理
本质上是一个过滤器链
从启动是可以获取到过滤器链:
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter
org.springframework.security.web.context.SecurityContextPersistenceFilter
org.springframework.security.web.header.HeaderWriterFilter
org.springframework.security.web.csrf.CsrfFilter
org.springframework.security.web.authentication.logout.LogoutFilter
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter
org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter
org.springframework.security.web.savedrequest.RequestCacheAwareFilter
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter
org.springframework.security.web.authentication.AnonymousAuthenticationFilter
org.springframework.security.web.session.SessionManagementFilter
org.springframework.security.web.access.ExceptionTranslationFilter
org.springframework.security.web.access.intercept.FilterSecurityInterceptor
其中三个过滤器:
FilterSecurityInterceptor
是一个方法级的权限过滤器,位于过滤链最底部
super.beforeInvocation(fi) 表示查看之前的 filter 是否通过。
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());表示真正的调用后台的服务。
ExceptionTranslationFilter
是个异常过滤器,用来处理在认证授权过程中抛出的异常
UsernamePasswordAuthenticationFilter
对/login 的 POST 请求做拦截
,校验表单中用户 名,密码。
两个重要接口
UserDetailsService
查询数据库用户名密码的过程
当什么也没写时只引入了springsecurity时,账号密码都是由框架生成的,而在实际中都是从数据库中查询出来。所以需要自定义逻辑控制认证逻辑
- 创建类继承UsernamePasswordAuthenticationFilter ,重写三个方法(判断用户名密码是否成功的过程)
- 创建类实现UserDetailsService,编写查询数据过程,返回User对象,这个User对象是安全框架提供的
PasswordEncoder
数据加密接口,用于返回User对象里面密码加密
// 表示把参数按照特定的解析规则进行解析
String encode(CharSequence rawPassword);
// 表示验证从存储中获取的编码密码与编码后提交的原始密码是否匹配。如果密码匹
配,则返回 true;如果不匹配,则返回 false。第一个参数表示需要被解析的密码。第二个
参数表示存储的密码。
boolean matches(CharSequence rawPassword, String encodedPassword);
// 表示如果解析的密码能够再次进行解析且达到更安全的结果则返回 true,否则返回
false。默认返回 false。
default boolean upgradeEncoding(String encodedPassword) {return false; }
web权限方案
用户认证
设置登录的用户名和密码的三种方式
配置文件
server.port=8111
spring.security.user.name=atguigu
spring.security.user.password=atguigu
配置类
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();String encode = passwordEncoder.encode("123");auth.inMemoryAuthentication().withUser("xyouzi").password(encode).roles("admin");}@BeanPasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}
}
自定义实现类
创建配置类,设置使用userDetailService实现类
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService userDetailsService;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());}@BeanPasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();} }
编写实现类,返回User对象,User对象有用户名密码和操作权限
@Service public class MyUserDetailService implements UserDetailsService {@Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {List<GrantedAuthority> role = AuthorityUtils.commaSeparatedStringToAuthorityList("role");return new User("xyouzi",new BCryptPasswordEncoder().encode("123"),role);} }
从数据库中查询认证
user表
添加依赖
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--mybatis-plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.0.5</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--lombok 用来简化实体类--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>
</dependencies>
实体类
@Data
public class Users {private Integer id;private String username;private String password; }
整合 MybatisPlus
@Repository
public interface UsersMapper extends BaseMapper<Users> {}
配置文件
server.port=8111#mysql 数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root
制作登录实现类
@Service
public class MyUserDetailService implements UserDetailsService {@Autowiredprivate UsersMapper usersMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {// username是前端传来的用户名,密码则由springsecurity内部帮你判断了QueryWrapper<Users> wrapper = new QueryWrapper<>();wrapper.eq("username",username);Users user = usersMapper.selectOne(wrapper);if (user == null) {throw new UsernameNotFoundException("用户不存在");}System.out.println(user);List<GrantedAuthority> role = AuthorityUtils.commaSeparatedStringToAuthorityList("role");return new User(user.getUsername(),new BCryptPasswordEncoder().encode(user.getPassword()),role);}
}
断点调试
自定义登录页面
引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
login.html
name="username"和name="password"不能修改
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head lang="en"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/><title>xx</title>
</head>
<body>
<h1>表单提交</h1>
<form action="/user/login" method="post"><input type="text" name="username" /><input type="text" name="password" /><input type="submit" />
</form>
</body>
</html>
配置类
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService userDetailsService;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());}@BeanPasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.formLogin() // 自定义登录页面.loginPage("/login.html") // 登录页面设置.loginProcessingUrl("/user/login") // 登录访问路径.defaultSuccessUrl("/test/index").permitAll() // 登录成功跳转路径.and().authorizeRequests().antMatchers("/","/test/hello","/user/login").permitAll() // 设置哪些路径可以直接访问,不需要认证.anyRequest().authenticated().and().csrf().disable(); // 关闭csrf防护}
}
Controller
通过上面的配置类设定后,访问/test/hello不需要用户名密码认证即可直接进入
访问/test/index则需要先通过认证,并且/test/index是登录成功后跳转的路径
@RestController
@RequestMapping("/test")
public class SecurityController {@GetMapping("hello")public String hello() {return "hello security";}@GetMapping("index")public String index() {return "hello index";}
}
授权
权限控制
hasAuthority方法
如果当前主体具有指定的权限,则返回true,否则返回false
在配置类中添加设置当前访问地址有哪些权限
.antMatchers("/test/index").hasAuthority("admins") // 只有admins权限才可访问/test/index
在MyUserDetailService类中,把返回的User对象设置权限
List<GrantedAuthority> role = AuthorityUtils.commaSeparatedStringToAuthorityList("admins");return new User(user.getUsername(),new BCryptPasswordEncoder().encode(user.getPassword()),role);
完整代码
MyUserDetailService
@Service
public class MyUserDetailService implements UserDetailsService {@Autowiredprivate UsersMapper usersMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {QueryWrapper<Users> wrapper = new QueryWrapper<>();wrapper.eq("username",username);Users user = usersMapper.selectOne(wrapper);if (user == null) {throw new UsernameNotFoundException("用户不存在");}System.out.println(user);List<GrantedAuthority> role = AuthorityUtils.commaSeparatedStringToAuthorityList("admins");return new User(user.getUsername(),new BCryptPasswordEncoder().encode(user.getPassword()),role);}
}
SecurityConfig
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService userDetailsService;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());}@BeanPasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.formLogin() // 自定义登录页面.loginPage("/login.html") // 登录页面设置.loginProcessingUrl("/user/login") // 登录访问路径.defaultSuccessUrl("/test/index").permitAll() // 登录成功跳转路径.and().authorizeRequests().antMatchers("/","/test/hello","/user/login").permitAll() // 设置哪些路径可以直接访问,不需要认证.antMatchers("/test/index").hasAuthority("admins") // 只有admins权限才可访问/test/index.anyRequest().authenticated().and().csrf().disable(); // 关闭csrf防护}
}
hasAnyAuthority方法
.antMatchers("/test/index").hasAnyAuthority("admins,manager") //设置多个权限可访问/test/index
角色控制
hasRole方法
如果当前主体具有指定的角色,则返回true,否则返回false
在配置类中添加设置当前访问地址有哪些角色
.antMatchers("/test/index").hasRole("sale")
hasAnyRole方法
.antMatchers("/test/index").hasAnyRole("sale,salee")
自定义403页面
配置类中添加并新建403页面unauth.html,命名可修改
http.exceptionHandling().accessDeniedPage("/unauth.html");
认证授权注解使用
@Secured
用户具有某个角色,才可以访问该注解下的方法
- 启动类开启注解
@EnableGlobalMethodSecurity(securedEnabled=true)
在controller里需要添加角色控制的方法上使用注解,设置角色
只有角色为ROLE_sale的用户才能访问该方法
@Secured({"ROLE_sale"})
@GetMapping("update")
public String update() {return "hello update";
}
在userDetailService设置角色
List<GrantedAuthority> role = AuthorityUtils.commaSeparatedStringToAuthorityList("manager,ROLE_sale");
@PreAuthorize
进入方法之前验证你有没有该权限
启动类开启注解
@EnableGlobalMethodSecurity(prePostEnabled = true)
在controller里需要添加角色控制的方法上使用注解
@PreAuthorize("hasAnyAuthority('manager')")@GetMapping("update")public String update() {return "hello update";}
在userDetailService设置角色
List<GrantedAuthority> role = AuthorityUtils.commaSeparatedStringToAuthorityList("manager,ROLE_sale");
用户注销
在登录页面添加一个退出连接按钮
<body>
登录成功<br> <a href="/logout">退出</a>
</body>
在配置类中添加退出映射地址
http.logout().logoutUrl("/logout").logoutSuccessUrl("/index").permitAll();
退出之后,是无法访问需要登录时才能访问的控制器!
记住我功能
原理分析
红字:第一次访问
篮字:非第一次访问
实现
新建数据表
CREATE TABLE `persistent_logins` (`username` varchar(64) NOT NULL,`series` varchar(64) NOT NULL,`token` varchar(64) NOT NULL,`last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE
CURRENT_TIMESTAMP,PRIMARY KEY (`series`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
配置类注入数据源,配置操作数据库对象
@Autowired
private DataSource dataSource;@Bean
public PersistentTokenRepository persistentTokenRepository() {JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();jdbcTokenRepository.setDataSource(dataSource);return jdbcTokenRepository;
}
配置类配置自动登录
.and().rememberMe() // 开启记住我功能.tokenRepository(persistentTokenRepository()) //设置操作数据库库对象.tokenValiditySeconds(60) // 60s过期.userDetailsService(userDetailsService)
登录页添加按钮
<input type="checkbox"name="remember-me"title="记住密码"/><br/>
csrf防护
参考https://blog.csdn.net/yjclsx/article/details/80349906
微服务权限方案
过程分析
在最上面简介也有文字叙述
项目目录概览
编写逻辑代码
sql
# Host: localhost (Version 5.7.19)
# Date: 2019-11-18 15:49:15
# Generator: MySQL-Front 6.1 (Build 1.26)#
# Structure for table "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='权限';#
# Data for table "acl_permission"
#INSERT INTO `acl_permission` VALUES ('1','0','全部数据',0,NULL,NULL,NULL,NULL,NULL,0,'2019-11-15 17:13:06','2019-11-15 17:13:06'),('1195268474480156673','1','权限管理',1,NULL,'/acl','Layout',NULL,NULL,0,'2019-11-15 17:13:06','2019-11-18 13:54:25'),('1195268616021139457','1195268474480156673','用户管理',1,NULL,'user/list','/acl/user/list',NULL,NULL,0,'2019-11-15 17:13:40','2019-11-18 13:53:12'),('1195268788138598401','1195268474480156673','角色管理',1,NULL,'role/list','/acl/role/list',NULL,NULL,0,'2019-11-15 17:14:21','2019-11-15 17:14:21'),('1195268893830864898','1195268474480156673','菜单管理',1,NULL,'menu/list','/acl/menu/list',NULL,NULL,0,'2019-11-15 17:14:46','2019-11-15 17:14:46'),('1195269143060602882','1195268616021139457','查看',2,'user.list','','',NULL,NULL,0,'2019-11-15 17:15:45','2019-11-17 21:57:16'),('1195269295926206466','1195268616021139457','添加',2,'user.add','user/add','/acl/user/form',NULL,NULL,0,'2019-11-15 17:16:22','2019-11-15 17:16:22'),('1195269473479483394','1195268616021139457','修改',2,'user.update','user/update/:id','/acl/user/form',NULL,NULL,0,'2019-11-15 17:17:04','2019-11-15 17:17:04'),('1195269547269873666','1195268616021139457','删除',2,'user.remove','','',NULL,NULL,0,'2019-11-15 17:17:22','2019-11-15 17:17:22'),('1195269821262782465','1195268788138598401','修改',2,'role.update','role/update/:id','/acl/role/form',NULL,NULL,0,'2019-11-15 17:18:27','2019-11-15 17:19:53'),('1195269903542444034','1195268788138598401','查看',2,'role.list','','',NULL,NULL,0,'2019-11-15 17:18:47','2019-11-15 17:18:47'),('1195270037005197313','1195268788138598401','添加',2,'role.add','role/add','/acl/role/form',NULL,NULL,0,'2019-11-15 17:19:19','2019-11-18 11:05:42'),('1195270442602782721','1195268788138598401','删除',2,'role.remove','','',NULL,NULL,0,'2019-11-15 17:20:55','2019-11-15 17:20:55'),('1195270621548568578','1195268788138598401','角色权限',2,'role.acl','role/distribution/:id','/acl/role/roleForm',NULL,NULL,0,'2019-11-15 17:21:38','2019-11-15 17:21:38'),('1195270744097742849','1195268893830864898','查看',2,'permission.list','','',NULL,NULL,0,'2019-11-15 17:22:07','2019-11-15 17:22:07'),('1195270810560684034','1195268893830864898','添加',2,'permission.add','','',NULL,NULL,0,'2019-11-15 17:22:23','2019-11-15 17:22:23'),('1195270862100291586','1195268893830864898','修改',2,'permission.update','','',NULL,NULL,0,'2019-11-15 17:22:35','2019-11-15 17:22:35'),('1195270887933009922','1195268893830864898','删除',2,'permission.remove','','',NULL,NULL,0,'2019-11-15 17:22:41','2019-11-15 17:22:41'),('1195349439240048642','1','讲师管理',1,NULL,'/edu/teacher','Layout',NULL,NULL,0,'2019-11-15 22:34:49','2019-11-15 22:34:49'),('1195349699995734017','1195349439240048642','讲师列表',1,NULL,'list','/edu/teacher/list',NULL,NULL,0,'2019-11-15 22:35:52','2019-11-15 22:35:52'),('1195349810561781761','1195349439240048642','添加讲师',1,NULL,'create','/edu/teacher/form',NULL,NULL,0,'2019-11-15 22:36:18','2019-11-15 22:36:18'),('1195349876252971010','1195349810561781761','添加',2,'teacher.add','','',NULL,NULL,0,'2019-11-15 22:36:34','2019-11-15 22:36:34'),('1195349979797753857','1195349699995734017','查看',2,'teacher.list','','',NULL,NULL,0,'2019-11-15 22:36:58','2019-11-15 22:36:58'),('1195350117270261762','1195349699995734017','修改',2,'teacher.update','edit/:id','/edu/teacher/form',NULL,NULL,0,'2019-11-15 22:37:31','2019-11-15 22:37:31'),('1195350188359520258','1195349699995734017','删除',2,'teacher.remove','','',NULL,NULL,0,'2019-11-15 22:37:48','2019-11-15 22:37:48'),('1195350299365969922','1','课程分类',1,NULL,'/edu/subject','Layout',NULL,NULL,0,'2019-11-15 22:38:15','2019-11-15 22:38:15'),('1195350397751758850','1195350299365969922','课程分类列表',1,NULL,'list','/edu/subject/list',NULL,NULL,0,'2019-11-15 22:38:38','2019-11-15 22:38:38'),('1195350500512206850','1195350299365969922','导入课程分类',1,NULL,'import','/edu/subject/import',NULL,NULL,0,'2019-11-15 22:39:03','2019-11-15 22:39:03'),('1195350612172967938','1195350397751758850','查看',2,'subject.list','','',NULL,NULL,0,'2019-11-15 22:39:29','2019-11-15 22:39:29'),('1195350687590748161','1195350500512206850','导入',2,'subject.import','','',NULL,NULL,0,'2019-11-15 22:39:47','2019-11-15 22:39:47'),('1195350831744782337','1','课程管理',1,NULL,'/edu/course','Layout',NULL,NULL,0,'2019-11-15 22:40:21','2019-11-15 22:40:21'),('1195350919074385921','1195350831744782337','课程列表',1,NULL,'list','/edu/course/list',NULL,NULL,0,'2019-11-15 22:40:42','2019-11-15 22:40:42'),('1195351020463296513','1195350831744782337','发布课程',1,NULL,'info','/edu/course/info',NULL,NULL,0,'2019-11-15 22:41:06','2019-11-15 22:41:06'),('1195351159672246274','1195350919074385921','完成发布',2,'course.publish','publish/:id','/edu/course/publish',NULL,NULL,0,'2019-11-15 22:41:40','2019-11-15 22:44:01'),('1195351326706208770','1195350919074385921','编辑课程',2,'course.update','info/:id','/edu/course/info',NULL,NULL,0,'2019-11-15 22:42:19','2019-11-15 22:42:19'),('1195351566221938690','1195350919074385921','编辑课程大纲',2,'chapter.update','chapter/:id','/edu/course/chapter',NULL,NULL,0,'2019-11-15 22:43:17','2019-11-15 22:43:17'),('1195351862889254913','1','统计分析',1,NULL,'/statistics/daily','Layout',NULL,NULL,0,'2019-11-15 22:44:27','2019-11-15 22:44:27'),('1195351968841568257','1195351862889254913','生成统计',1,NULL,'create','/statistics/daily/create',NULL,NULL,0,'2019-11-15 22:44:53','2019-11-15 22:44:53'),('1195352054917074946','1195351862889254913','统计图表',1,NULL,'chart','/statistics/daily/chart',NULL,NULL,0,'2019-11-15 22:45:13','2019-11-15 22:45:13'),('1195352127734386690','1195352054917074946','查看',2,'daily.list','','',NULL,NULL,0,'2019-11-15 22:45:30','2019-11-15 22:45:30'),('1195352215768633346','1195351968841568257','生成',2,'daily.add','','',NULL,NULL,0,'2019-11-15 22:45:51','2019-11-15 22:45:51'),('1195352547621965825','1','CMS管理',1,NULL,'/cms','Layout',NULL,NULL,0,'2019-11-15 22:47:11','2019-11-18 10:51:46'),('1195352856645701633','1195353513549205505','查看',2,'banner.list','',NULL,NULL,NULL,0,'2019-11-15 22:48:24','2019-11-15 22:48:24'),('1195352909401657346','1195353513549205505','添加',2,'banner.add','banner/add','/cms/banner/form',NULL,NULL,0,'2019-11-15 22:48:37','2019-11-18 10:52:10'),('1195353051395624961','1195353513549205505','修改',2,'banner.update','banner/update/:id','/cms/banner/form',NULL,NULL,0,'2019-11-15 22:49:11','2019-11-18 10:52:05'),('1195353513549205505','1195352547621965825','Bander列表',1,NULL,'banner/list','/cms/banner/list',NULL,NULL,0,'2019-11-15 22:51:01','2019-11-18 10:51:29'),('1195353672110673921','1195353513549205505','删除',2,'banner.remove','','',NULL,NULL,0,'2019-11-15 22:51:39','2019-11-15 22:51:39'),('1195354076890370050','1','订单管理',1,NULL,'/order','Layout',NULL,NULL,0,'2019-11-15 22:53:15','2019-11-15 22:53:15'),('1195354153482555393','1195354076890370050','订单列表',1,NULL,'list','/order/list',NULL,NULL,0,'2019-11-15 22:53:33','2019-11-15 22:53:58'),('1195354315093282817','1195354153482555393','查看',2,'order.list','','',NULL,NULL,0,'2019-11-15 22:54:12','2019-11-15 22:54:12'),('1196301740985311234','1195268616021139457','分配角色',2,'user.assgin','user/role/:id','/acl/user/roleForm',NULL,NULL,0,'2019-11-18 13:38:56','2019-11-18 13:38:56');#
# Structure for table "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;#
# Data for table "acl_role"
#INSERT INTO `acl_role` VALUES ('1','普通管理员',NULL,NULL,0,'2019-11-11 13:09:32','2019-11-18 10:27:18'),('1193757683205607426','课程管理员',NULL,NULL,0,'2019-11-11 13:09:45','2019-11-18 10:25:44'),('1196300996034977794','test',NULL,NULL,0,'2019-11-18 13:35:58','2019-11-18 13:35:58');#
# Structure for table "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='角色权限';#
# Data for table "acl_role_permission"
#INSERT INTO `acl_role_permission` VALUES ('1196301979754455041','1','1',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301979792203778','1','1195268474480156673',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301979821563906','1','1195268616021139457',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301979842535426','1','1195269143060602882',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301979855118338','1','1195269295926206466',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301979880284161','1','1195269473479483394',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301979913838593','1','1195269547269873666',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301979926421506','1','1196301740985311234',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301979951587330','1','1195268788138598401',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980014501889','1','1195269821262782465',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980035473410','1','1195269903542444034',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980052250626','1','1195270037005197313',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980077416450','1','1195270442602782721',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980094193665','1','1195270621548568578',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980119359489','1','1195268893830864898',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980136136706','1','1195270744097742849',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980249382913','1','1195270810560684034',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980270354434','1','1195270862100291586',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980287131649','1','1195270887933009922',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980303908866','1','1195349439240048642',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980320686082','1','1195349699995734017',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980345851905','1','1195349979797753857',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980362629121','1','1195350117270261762',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980383600641','1','1195350188359520258',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980408766465','1','1195349810561781761',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980421349378','1','1195349876252971010',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980438126593','1','1195350299365969922',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980450709506','1','1195350397751758850',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980501041153','1','1195350612172967938',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980517818370','1','1195350500512206850',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980538789889','1','1195350687590748161',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980622675970','1','1195350831744782337',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980639453186','1','1195350919074385921',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980660424705','1','1195351159672246274',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980677201922','1','1195351326706208770',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980698173441','1','1195351566221938690',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980714950658','1','1195351020463296513',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980723339266','1','1195351862889254913',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980744310786','1','1195351968841568257',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980761088001','1','1195352215768633346',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980777865217','1','1195352054917074946',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980794642434','1','1195352127734386690',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980811419650','1','1195352547621965825',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980828196865','1','1195353513549205505',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980844974082','1','1195352856645701633',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980861751298','1','1195352909401657346',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980886917122','1','1195353051395624961',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980928860162','1','1195353672110673921',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980954025986','1','1195354076890370050',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980970803201','1','1195354153482555393',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196301980987580418','1','1195354315093282817',1,'2019-11-18 13:39:53','2019-11-18 13:39:53'),('1196305293070077953','1','1',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293099438081','1','1195268474480156673',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293120409602','1','1195268616021139457',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293153964034','1','1195269143060602882',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293183324162','1','1195269295926206466',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293212684290','1','1195269473479483394',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293237850114','1','1195269547269873666',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293271404545','1','1196301740985311234',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293485314049','1','1195268788138598401',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293506285569','1','1195269821262782465',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293527257089','1','1195269903542444034',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293552422914','1','1195270037005197313',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293565005825','1','1195270442602782721',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293594365954','1','1195270621548568578',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293611143169','1','1195268893830864898',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293627920385','1','1195270744097742849',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293657280513','1','1195349439240048642',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293674057729','1','1195349699995734017',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293690834946','1','1195349979797753857',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293716000770','1','1195350117270261762',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293736972290','1','1195350188359520258',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293749555202','1','1195349810561781761',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293766332417','1','1195349876252971010',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293795692546','1','1195350299365969922',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293812469762','1','1195350397751758850',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293837635586','1','1195350612172967938',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293858607106','1','1195350500512206850',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293875384322','1','1195350687590748161',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293892161538','1','1195350831744782337',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293950881794','1','1195350919074385921',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305293976047617','1','1195351159672246274',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305294127042561','1','1195351326706208770',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305294156402690','1','1195351566221938690',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305294177374209','1','1195351862889254913',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305294194151425','1','1195351968841568257',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305294223511554','1','1195352215768633346',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305294240288770','1','1195352054917074946',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305294248677377','1','1195352127734386690',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305294248677378','1','1195352547621965825',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305294319980546','1','1195353513549205505',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305294319980547','1','1195352856645701633',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305294319980548','1','1195352909401657346',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305294378700802','1','1195353051395624961',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305294378700803','1','1195353672110673921',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305294458392577','1','1195354076890370050',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305294483558402','1','1195354153482555393',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305294500335618','1','1195354315093282817',1,'2019-11-18 13:53:03','2019-11-18 13:53:03'),('1196305566656139266','1','1',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305566689693698','1','1195268474480156673',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305566706470913','1','1195268616021139457',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305566740025346','1','1195269143060602882',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305566756802561','1','1195269295926206466',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305566781968385','1','1195269473479483394',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305566811328514','1','1195269547269873666',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305566828105730','1','1196301740985311234',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305566853271554','1','1195268788138598401',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305566878437378','1','1195269821262782465',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305566895214593','1','1195269903542444034',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305566916186113','1','1195270037005197313',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305566949740546','1','1195270442602782721',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305566966517761','1','1195270621548568578',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305566991683585','1','1195268893830864898',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567012655106','1','1195270744097742849',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567029432322','1','1195270810560684034',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567042015233','1','1195270862100291586',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567100735490','1','1195270887933009922',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567117512705','1','1195349439240048642',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567142678530','1','1195349699995734017',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567155261442','1','1195349979797753857',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567172038658','1','1195350117270261762',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567188815873','1','1195350188359520258',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567218176001','1','1195349810561781761',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567234953217','1','1195349876252971010',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567251730434','1','1195350299365969922',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567272701954','1','1195350397751758850',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567289479170','1','1195350612172967938',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567310450690','1','1195350500512206850',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567327227905','1','1195350687590748161',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567448862722','1','1195350831744782337',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567478222850','1','1195350919074385921',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567495000065','1','1195351159672246274',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567520165889','1','1195351326706208770',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567541137409','1','1195351566221938690',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567570497538','1','1195351862889254913',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567587274754','1','1195351968841568257',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567604051970','1','1195352215768633346',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567633412098','1','1195352054917074946',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567683743745','1','1195352127734386690',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567721492481','1','1195352547621965825',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567742464002','1','1195353513549205505',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567771824129','1','1195352856645701633',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567792795650','1','1195352909401657346',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567809572866','1','1195353051395624961',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567843127298','1','1195353672110673921',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567868293122','1','1195354076890370050',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567885070338','1','1195354153482555393',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196305567910236162','1','1195354315093282817',1,'2019-11-18 13:54:08','2019-11-18 13:54:08'),('1196312702601695234','1','1',0,'2019-11-18 14:22:29','2019-11-18 14:22:29'),('1196312702652026881','1','1195268474480156673',0,'2019-11-18 14:22:29','2019-11-18 14:22:29'),('1196312702668804098','1','1195268616021139457',0,'2019-11-18 14:22:29','2019-11-18 14:22:29'),('1196312702698164226','1','1195269143060602882',0,'2019-11-18 14:22:29','2019-11-18 14:22:29'),('1196312702723330049','1','1195269295926206466',0,'2019-11-18 14:22:29','2019-11-18 14:22:29'),('1196312702744301569','1','1195269473479483394',0,'2019-11-18 14:22:29','2019-11-18 14:22:29'),('1196312702765273089','1','1195269547269873666',0,'2019-11-18 14:22:29','2019-11-18 14:22:29'),('1196312702790438913','1','1196301740985311234',0,'2019-11-18 14:22:29','2019-11-18 14:22:29'),('1196312702945628161','1','1195268788138598401',0,'2019-11-18 14:22:29','2019-11-18 14:22:29'),('1196312702970793985','1','1195269821262782465',0,'2019-11-18 14:22:29','2019-11-18 14:22:29'),('1196312703000154114','1','1195269903542444034',0,'2019-11-18 14:22:29','2019-11-18 14:22:29'),('1196312703025319938','1','1195270037005197313',0,'2019-11-18 14:22:29','2019-11-18 14:22:29'),('1196312703046291458','1','1195270442602782721',0,'2019-11-18 14:22:29','2019-11-18 14:22:29'),('1196312703063068673','1','1195270621548568578',0,'2019-11-18 14:22:29','2019-11-18 14:22:29'),('1196312703084040193','1','1195268893830864898',0,'2019-11-18 14:22:29','2019-11-18 14:22:29'),('1196312703113400321','1','1195270744097742849',0,'2019-11-18 14:22:29','2019-11-18 14:22:29'),('1196312703134371842','1','1195270810560684034',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703159537665','1','1195270862100291586',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703184703490','1','1195270887933009922',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703209869313','1','1195349439240048642',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703230840834','1','1195349699995734017',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703251812354','1','1195349979797753857',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703272783873','1','1195350117270261762',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703293755394','1','1195350188359520258',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703327309826','1','1195349810561781761',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703348281345','1','1195349876252971010',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703365058561','1','1195350299365969922',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703386030082','1','1195350397751758850',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703440556034','1','1195350612172967938',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703486693378','1','1195350500512206850',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703511859202','1','1195350687590748161',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703654465537','1','1195350831744782337',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703683825665','1','1195350919074385921',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703700602882','1','1195351159672246274',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703717380098','1','1195351326706208770',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703738351618','1','1195351566221938690',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703759323137','1','1195351020463296513',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703776100353','1','1195351862889254913',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703792877570','1','1195351968841568257',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703830626305','1','1195352215768633346',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703843209217','1','1195352054917074946',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703868375041','1','1195352127734386690',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703889346561','1','1195352547621965825',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703901929473','1','1195353513549205505',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703918706689','1','1195352856645701633',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703952261121','1','1195352909401657346',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703973232642','1','1195353051395624961',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312703990009857','1','1195353672110673921',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312704048730114','1','1195354076890370050',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312704069701633','1','1195354153482555393',0,'2019-11-18 14:22:30','2019-11-18 14:22:30'),('1196312704094867457','1','1195354315093282817',0,'2019-11-18 14:22:30','2019-11-18 14:22:30');#
# Structure for table "acl_user"
#CREATE TABLE `acl_user` (`id` char(19) NOT NULL COMMENT '会员id',`username` varchar(20) NOT NULL DEFAULT '' COMMENT '微信openid',`password` varchar(32) 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='用户表';#
# Data for table "acl_user"
#INSERT INTO `acl_user` VALUES ('1','admin','96e79218965eb72c92a549dd5a330112','admin','',NULL,0,'2019-11-01 10:39:47','2019-11-01 10:39:47'),('2','test','96e79218965eb72c92a549dd5a330112','test',NULL,NULL,0,'2019-11-01 16:36:07','2019-11-01 16:40:08');#
# Structure for table "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;#
# Data for table "acl_user_role"
#INSERT INTO `acl_user_role` VALUES ('1','1','2',0,'2019-11-11 13:09:53','2019-11-11 13:09:53');
密码处理工具类
/*** 密码处理工具类*/
@Component
public class DefaultPasswordEncoder implements PasswordEncoder {public DefaultPasswordEncoder() {this(-1);}public DefaultPasswordEncoder(int strenth) {}// 密码加密@Overridepublic String encode(CharSequence charSequence) {String encrypt = MD5.encrypt(charSequence.toString());return encrypt;}// 密码比对@Overridepublic boolean matches(CharSequence charSequence, String s) {return s.equals(MD5.encrypt(charSequence.toString()));}
}
token工具类
/*** token工具类*/
@Component
public class TokenManager {// 过期时间private long tokenExpiration = 24*60*60*1000;// 密钥private String tokenSignKey = "123456";// 根据传入的用户名生成tokenpublic String createToken(String username) {String token = Jwts.builder().setSubject(username)// 设置过期时间.setExpiration(new Date(System.currentTimeMillis() +tokenExpiration))// 设置签名.signWith(SignatureAlgorithm.HS512,tokenSignKey).compressWith(CompressionCodecs.GZIP).compact();return token;}// 根据token获取用户信息public String getUserFromToken(String token) {String user = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody().getSubject();return user;}public void removeToken(String token) {//jwttoken 无需删除,客户端扔掉即可。}
}
退出处理器
/**
* 推出处理器
*/
@Component
public class TokenLogoutHandler implements LogoutHandler {private TokenManager tokenManager;private RedisTemplate redisTemplate;public TokenLogoutHandler(TokenManager tokenManager, RedisTemplate redisTemplate) {this.tokenManager = tokenManager;this.redisTemplate = redisTemplate;}@Overridepublic void logout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) {String token = httpServletRequest.getHeader("token"); // 从头中获取tokenif (token != null) { // 如果token存在,则移除tokenManager.removeToken(token);// 从token中获取用户名String user = tokenManager.getUserFromToken(token);// 在redis中删除该用户信息redisTemplate.delete(user);}ResponseUtil.out(httpServletResponse, R.ok());}
}
未授权统一处理
/*** 未授权统一处理*/
public class UnauthorizedEntryPoint implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException{ResponseUtil.out(response, R.error());}
}
security认证过滤器
先创建两个实体类
@Data
public class User implements Serializable {private String username;private String password;private String nickName;private String salt;private String token;
}
@Data
@Slf4j
public class SecurityUser implements UserDetails {//当前登录用户private transient User currentUserInfo;//当前权限private List<String> permissionValueList;public SecurityUser() {}public SecurityUser(User user) {if (user != null) {this.currentUserInfo = user;}}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {Collection<GrantedAuthority> authorities = new ArrayList<>();for(String permissionValue : permissionValueList) {if(StringUtils.isEmpty(permissionValue)) continue;SimpleGrantedAuthority authority = newSimpleGrantedAuthority(permissionValue);authorities.add(authority);}return authorities;}@Overridepublic String getPassword() {return currentUserInfo.getPassword();}@Overridepublic String getUsername() {return currentUserInfo.getUsername();}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;
认证过滤器
/*** 认证过滤器*/
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {private AuthenticationManager authenticationManager;private TokenManager tokenManager;private RedisTemplate redisTemplate;public TokenLoginFilter(AuthenticationManager authenticationManager,TokenManager tokenManager, RedisTemplate redisTemplate) {this.authenticationManager = authenticationManager;this.tokenManager = tokenManager;this.redisTemplate = redisTemplate;this.setPostOnly(false);this.setRequiresAuthenticationRequestMatcher(newAntPathRequestMatcher("/admin/acl/login","POST"));}// 获取表单提交的用户名和密码@Overridepublic Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {try {User user = new ObjectMapper().readValue(request.getInputStream(), User.class);// 这个过程会调用UserDetails去查询数据库返回用户信息return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(),user.getPassword(),new ArrayList<>()));} catch (IOException e) {e.printStackTrace();throw new RuntimeException();}}// 认证成功调用的方法@Overrideprotected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {// 认证成功,得到用户信息SecurityUser user = (SecurityUser) authResult.getPrincipal();// 根据用户名生成tokenString token = tokenManager.createToken(user.getUsername());// 将用户名为key,用户权限列表为value存入redisredisTemplate.opsForValue().set(user.getCurrentUserInfo().getUsername(),user.getPermissionValueList());// 返回tokenResponseUtil.out(response, R.ok().data("token",token));}// 认证失败调用的方法@Overrideprotected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {ResponseUtil.out(response, R.error());}
}
secutiry授权过滤器
/*** 授权过滤器*/
public class TokenAuthFilter extends BasicAuthenticationFilter {private TokenManager tokenManager;private RedisTemplate redisTemplate;public TokenAuthFilter(AuthenticationManager authManager,TokenManager tokenManager, RedisTemplate redisTemplate) {super(authManager);this.tokenManager = tokenManager;this.redisTemplate = redisTemplate;}@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {// 获取当前认证成功的用户权限信息UsernamePasswordAuthenticationToken authRequest = getAuthentication(request);// 如果有权限,则放到全县上下文中if (authRequest != null){SecurityContextHolder.getContext().setAuthentication(authRequest);}chain.doFilter(request,response);}private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {// 从header中获取tokenString token = request.getHeader("token");if (token != null) {// 根据token获取用户名String username = tokenManager.getUserFromToken(token);// 根据username从redeis中获取权限列表List<String> permissionValueList = (List<String>) redisTemplate.opsForValue().get(username);Collection<GrantedAuthority> authority = new ArrayList<>();for (String s : permissionValueList) {SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(s);authority.add(simpleGrantedAuthority);}return new UsernamePasswordAuthenticationToken(username,token,authority);}return null;}
}
UserDetailServiceImpl类
在service模块中写这个类,在这个类中进行查询数据库
/*** 在这个类中查询数据库*/
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate UserService userService;@Autowiredprivate PermissionService permissionService;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//根据用户名查询数据User user = userService.selectByUsername(username);//判断if(user == null) {throw new UsernameNotFoundException("用户不存在");}com.atguigu.entity.User curUser = new com.atguigu.entity.User();BeanUtils.copyProperties(user,curUser);//根据用户查询用户权限列表List<String> permissionValueList = permissionService.selectPermissionValueByUserId(user.getId());SecurityUser securityUser = new SecurityUser();securityUser.setCurrentUserInfo(curUser);securityUser.setPermissionValueList(permissionValueList);return securityUser;}
}
测试使用
完整代码:https://gitee.com/xYouzi/aclSecurity
因为还有网关模块,前端页面,不好展示太多,所以这里展示如何使用,可直接clone代码尝试
- 启动nacos和redis(需要随之修改java代码中的配置文件)
- 启动后端代码的两个模块:ApiGatewayApplication、ServiceAclApplication
- 启动前端代码(npm run dev)
后端代码可直接使用在其他项目上,只需根据需求修改代码
springboot整合springsecurity安全框架(后端spring_security模块代码可直接使用,根据需求自定义修改)相关推荐
- SpringBoot整合SpringSecurity+Redis权限控制
SpringBoot整合SpringSecurity+Redis权限控制 1.认识SpringSecurity 2.效果截图 2.1.登录接口 2.2.注册接口 2.3.管理员权限接口 2.4.普通用 ...
- SpringBoot整合SpringSecurity实现权限控制(五):用户管理
系列文章目录 <SpringBoot整合SpringSecurity实现权限控制(一):实现原理> <SpringBoot整合SpringSecurity实现权限控制(二):权限数据 ...
- Springboot整合SpringSecurity 04-启用登出logout功能
Springboot整合SpringSecurity 04-启用登出logout功能 前面Springboot整合SpringSecurity 02-使用自定义登陆页面我们讲过了SpringSecur ...
- SpringBoot整合thymeleaf之模糊查询操作模块
SpringBoot整合thymeleaf之模糊查询操作模块 引言 1.一般情况下,Mybatis的模糊查询操作 模糊查询操作 2.在实战中的模糊查询操作 web页面提交数据 <form act ...
- SpringBoot 整合 Dozer 映射框架
SpringBoot 整合 Dozer 映射框架 1. Dozer 介绍 2. 为什么要使用映射框架 Dozer 3. Dozer 映射框架的使用 1. Dozer 介绍 Dozer 是一个 Java ...
- Springboot 整合SpringSecurity实现账号密码+手机验证码登陆
Springboot 整合SpringSecurity实现账号密码+手机验证码登陆 示例说明 版本 示例安装 Spring-security 介绍 为什么不用 shiro Spring-Securit ...
- Springboot整合Quartz任务框架
分享一篇关于Springboot整合Quartz任务框架在实际开发中的使用,基于SpringBoot2.0+Mybatis+Oracle开发 1. 导入jar包 <!-- 定时任务 --&g ...
- # SpringBoot 整合 Activiti 工作流框架
SpringBoot 整合 Activiti 工作流框架 Activiti 介绍 Activiti是一个开源的工作流引擎,它实现了BPMN 2.0规范,可以发布设计好的流程定义,并通过api进行流程调 ...
- SpringBoot + MyBatis-Plus +SpringSecurity +Thymeleaf +LayUI 通用业务模块集成安全认证
1.基础技术框架 技术名称 版本 SpringBoot 2.1.0.RELEASE Mybatis-Plus 3.4.1 Lombok 1.18.2 MySQL8 8.0.13 Alibaba Dru ...
最新文章
- DBA(二):percona软件、innobackupex备份与恢复
- php make test 作用,larablog 系列文章 06 - 测试:使用 PHPUnit 进行单元和功能测试
- 【Elasticsearch】不常用 length filer、ngram filter、trim filter、truncate filter、unique filter、synonym token
- linux系统 设置网卡ping通主机连上外网
- 编译php的问题,php编译常见错误
- 2022电工(技师)考试题库模拟考试平台操作
- OpenCV:图像检索
- python刷今日头条访问量_python爬虫实战:刷某博客站点的访问量(转)
- 计算机断网后怎么连接网络连接,win7系统中网络经常掉线断网后又自动连接上怎么办...
- 百度有啊 真的还有啊
- mgo 的 session 与连接池
- [案例分享]根据现有产品数据,如何做一次数据分析呢?
- 老树发新芽-前后端分离实践
- .net 微信开发
- 特征工程之One-Hot编码、label-encoding、自定义编码
- Android 绘制渐变色
- Java实现短信验证码(阿里云短信服务)
- ANSYS Workbench 16 - 黄志新(图书阅读总结)
- Docker三大核心之容器
- 博士一篇SCI四区即可入职,安家费120万,直接进编,无非升即走!
热门文章
- fatal: 无法访问 ‘‘github.com/“:GnuTLS recv error (-110): The TLS connection was non-properly terminated.
- 【李刚-21天通关Python-03】之 运算符
- 模板会有多层镜像_【保持最新版本】EVE-NG 新版模板,镜像。2020-12-27有更新
- Unity DOTS1.0安装
- 尔雅云Wi-Fi云计费平台应用白皮书_V1.3.2版本
- Mac 本地下载安装Nginx
- 实用健指操:让你告别鼠标手、键盘手
- 桌面一直出现计算机符号,电脑桌面图标有箭头怎么办 电脑桌面图片箭头去掉方法【图文】...
- 【Vue3.0 + Element-plus】el-tree树状结构节点前箭头样式修改
- ViewBinding 与 Kotlin 委托双剑合璧