Spring Security

文章目录

  • 1. SpringSecurity 框架简介
    • 1.1 概要
    • 1.2 同款产品对比
      • 1.2.1 Spring Security
      • 1.2.2 Shiro
  • 2.SpringSecurity中的hollow word
    • 2.1 新手入门
    • 2.2权限管理中的相关概念
      • 2.2.1 主体
      • 2.2.2 认证
      • 2.2.3 授权
    • 2.3 SpringSecurity 基本原理
    • 2.4 两个重要的接口
  • 3. SpringSecurity Web 权限方案
    • 3.1 设置登录的用户名和密码
      • 3.1.1 方式一:用过配置文件
      • 3.1.2 方式二:通过配置类
      • 3.1.3 自定义编写实现类
    • 3.2 实现数据库认证来完成用户登录
      • 3.2.1 添加相关依赖
      • 3.2.2 创建数据库表和对应的实体类
      • 3.2.3创建对应的实体类
      • 3.2.4整合MyBatis-plus,创建接口整合MyBatis-plus
      • 3.2.5 在MyUserDetailService调用mapper方法查询数据库进行用户认证
      • 3.2.6在启动类加注解MapperScan
      • 3.2.7配置数据库信息
    • 3.3 未认证请求跳转到登录页
      • 3.3.1 编写控制器
      • 3.3.2 编写配置类放行登录页面以及静态资源
      • 3.3.3 编写登录页面
    • 3.4 基于角色或权限进行访问控制
      • 3.4.1 hasAuthority方法
      • 3.4.2 hasAnyAuthority 方法
      • 3.4.3 hasRole 方法
      • 3.4.4 hasAnyRole
      • 3.5自定义403页面
    • 3.6 注解的使用
      • 3.6.1 @Secured
      • 3.6.2@PreAuthorize
      • 3.6.3 @PostAuthorize
      • 3.6.4@PostFilter
      • 3.6.5 @PreFilter
    • 3.7 用户注销
    • 3.8 基于数据库在自动登录
      • 3.8.1 实现过程
      • 3.8.2 具体实现
    • 3.9 CSRF
      • 3.9.1 CSRF 理解
  • 4.SpringSecurity微服务权限方案
    • 4.1 什么是微服务
      • 4.1.1、微服务由来
      • 4.1. 2、微服务优势
      • 4.1.3、微服务本质
    • 4.2 微服务认证与授权实现思路
      • 4.2.1、认证授权过程分析
  • 5.权限认证小案例
    • 5.1 微服务权限管理案例的主要实现功能
    • 5.2.权限管理数据模型
    • 5.3相关技术的介绍
    • 5.4 搭建环境
    • 5.5具体代码的编写
      • 5.5.1 编写common里面的工具类
      • 5.5.2 编写springsecurity认证授权工具类和处理器

1. SpringSecurity 框架简介

1.1 概要

Spring 是非常流行和成功的 Java 应用开发框架,Spring Security 正是 Spring 家族中的成员。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。
正如你可能知道的关于安全方面的两个主要区域是 “认证”和“授权” (或者访问控制),一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权 (Authorization)两个部分,这两点也是 Spring Security 重要核心功能。

  1. 用户认证指的是:验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。通俗点说就是系统认为用户是否能登录
  2. 用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。通俗点讲就是系统判断用户是否有权限去做某些事情。

1.2 同款产品对比

1.2.1 Spring Security

Spring 技术栈的组成部分。
SpringSecurity 特点:

  • 和 Spring 无缝整合。
  • 全面的权限控制。
  • 专门为 Web 开发而设计。
  1. 旧版本不能脱离 Web 环境使用。
  2. 新版本对整个框架进行了分层抽取,分成了核心模块和 Web 模块。单独引入核心模块就可以脱离 Web 环境。
  • 重量级

1.2.2 Shiro

Apache 旗下的轻量级权限控制框架。

特点:

  • 轻量级。Shiro 主张的理念是把复杂的事情变简单。针对对性能有更高要求的互联网应用有更好表现。
  • 通用性。
  1. 好处:不局限于 Web 环境,可以脱离 Web 环境使用。
  2. 缺陷:在 Web 环境下一些特定的需求需要手动编写代码定制。

2.SpringSecurity中的hollow word

2.1 新手入门

  1. 创建一个名为SpringSecurity的springboot项目
  2. 添加依赖
    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starterartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-securityartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
    dependencies>
  1. 编写一个controller
@RestController
@RequestMapping("/text")
public class TextController {

    @GetMapping("/hollow")
    public String hollow(){
        return "hollow";
    }
}
  1. 用浏览器访问接口会出现以下界面
    Spring Security_第1张图片
  2. 用户名为user,密码会出现的控制台
    Spring Security_第2张图片
    进行登录(每次密码会发生变化)
  3. 会出现以下结果
    Spring Security_第3张图片

2.2权限管理中的相关概念

2.2.1 主体

  • 英文单词:principal
  • 使用系统的用户或设备或从其他系统远程登录的用户等等。简单说就是谁使用系统谁就是主体。

2.2.2 认证

  • 英文单词:authentication
  • 权限管理系统确认一个主体的身份,允许主体进入系统。简单说就是“主体”证明自己是谁。
  • 笼统的认为就是以前所做的登录操作。

2.2.3 授权

  • 英文单词:authorization
  • 将操作系统的“权力”“授予”“主体”,这样主体就具备了操作系统中特定功能的能力。
  • 所以简单来说,授权就是给用户分配权限。

2.3 SpringSecurity 基本原理

SpringSecurity 本质是一个过滤器链:
常见的三个过滤器:

  1. FilterSecurityInterceptor:是一个方法级的权限过滤器, 基本位于过滤链的最底部。
  2. ExceptionTranslationFilter:是个异常过滤器,用来处理在认证授权过程中抛出的异常。
  3. UsernamePasswordAuthenticationFilter :对/login 的 POST 请求做拦截,校验表单中用户名,密码。

2.4 两个重要的接口

  1. UserDetailsService:查询数据库用户名和密码的过程
    具体步骤
    1. 传类继承UsernamePasswordAuthenticationFilter,重写三个方法
    2. 创建实体类UserDetailService,编写访问数据的过程,返回User对象,这个User对象是安全框架提供的对象

  2. PasswordEncoder:数据加密接口,用于返回User对象里面的密码加密

3. SpringSecurity Web 权限方案

3.1 设置登录的用户名和密码

3.1.1 方式一:用过配置文件

spring.security.user.name=admin # 登录的用户名
spring.security.user.password=123456 #登录的密码

3.1.2 方式二:通过配置类

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String password = passwordEncoder.encode("123456");//加密
        auth.inMemoryAuthentication().withUser("admin").password(password).roles("admin");//将信息放入内存
    }

    @Bean
    PasswordEncoder password(){
       return new BCryptPasswordEncoder();
    }
}

3.1.3 自定义编写实现类

步骤:

  1. 创建配置类,设置使用哪个userDetailsService实现类
  2. 编写实现类返回User对戏,User对戏有用户名、密码操作权限
    写配置类
@Configuration
public class SecurityConfigureText extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailService myUserDetailService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailService).passwordEncoder(password());
    }

    @Bean
    PasswordEncoder password(){
        return new BCryptPasswordEncoder();
    }
}

编写实现类

@Service
public class MyUserDetailService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        List<GrantedAuthority> auths= AuthorityUtils.commaSeparatedStringToAuthorityList("role");//分配权限
        return new User("admin",new BCryptPasswordEncoder().encode("123456"),auths);
    }
}

3.2 实现数据库认证来完成用户登录

3.2.1 添加相关依赖

 <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-boot-starterartifactId>
            <version>3.0.5version>
        dependency>
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
        dependency>
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
        dependency>

3.2.2 创建数据库表和对应的实体类

create table users(
 id bigint primary key auto_increment,
username varchar(20) unique not null,
password varchar(100)
);

3.2.3创建对应的实体类

创建一个名为users的实体类

@Data
@ToString
public class Users {
    private  Integer id;

    private String username;

    private String password;
}

3.2.4整合MyBatis-plus,创建接口整合MyBatis-plus

@Repository
public interface UsersMapper extends BaseMapper<Users> {
}

3.2.5 在MyUserDetailService调用mapper方法查询数据库进行用户认证

@Service
public class MyUserDetailService implements UserDetailsService {

    @Autowired
    private UsersMapper usersMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //调用userMapper方法,根据用户名查询数据库
        QueryWrapper<Users> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",username);
        Users users = usersMapper.selectOne(queryWrapper);
        //用户不存在,
        if(users==null)
        {
          throw new UsernameNotFoundException("用户名不存在");
        }
        List<GrantedAuthority> auths= AuthorityUtils.commaSeparatedStringToAuthorityList("role");//分配权限
        //从数据库中获得的user对象返回用户名和密码
        return new User(users.getUsername(),new BCryptPasswordEncoder().encode(users.getPassword()),auths);
    }
}

3.2.6在启动类加注解MapperScan

@SpringBootApplication
@MapperScan(basePackages = "com.example.spring_security.mapper")
public class SpringSecurityApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringSecurityApplication.class, args);
    }

}

3.2.7配置数据库信息

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/demo?serverTimezone=GMT%2B8
    username: root
    password: 199866

3.3 未认证请求跳转到登录页

3.3.1 编写控制器

@RestController
@RequestMapping("/text")
public class TextController {

    @GetMapping("/hollow")
    public String hollow(){
        return "hollow";
    }

    @GetMapping("/index")
    public String index()
    {
        return "index";
    }
    @GetMapping("/word")
    public String word()
    {
        return "word";
    }
}

3.3.2 编写配置类放行登录页面以及静态资源

@Configuration
public class SecurityConfigureText extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailService myUserDetailService;



    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailService).passwordEncoder(password());
    }

    @Bean
    PasswordEncoder password(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin() //自定义自己编写的登录页面
            .loginPage("/login.html") //登录页面设置
            .loginProcessingUrl("/user/login") //登录访问路径  框架以及写好
            .defaultSuccessUrl("/text/index").permitAll() //登录成功之后页面跳转
            .and().authorizeRequests()
                .antMatchers("/","/text/hollow","/user/login").permitAll() //设置哪些路径可以直接访问不需要认证
            .anyRequest().authenticated() 
            .and().csrf().disable();//关闭csrf保护

    }
}

3.3.3 编写登录页面

login.html

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
  <form action="/user/login" method="post">
      用户名:<input type="text" name="username">
      <br>
      密码:<input type="password" name="password">
      <br>
      <input type="submit" value="登录">
  form>
body>
html>

Spring Security_第4张图片

3.4 基于角色或权限进行访问控制

3.4.1 hasAuthority方法

如果当前主题的访问权限返回true否则返回false
没有访问权限403(type=Forbidden,status=403)

  1. 在配置类设置当前访问地址有哪些权限
    Spring Security_第5张图片
  2. 在UserDetailsService,把返回的对象设置权限
    Spring Security_第6张图片

3.4.2 hasAnyAuthority 方法

如果当前的主体有任何提供的角色(给定的作为一个逗号分隔的字符串列表)的话,返回true.

Spring Security_第7张图片

3.4.3 hasRole 方法

如果用户具备给定角色就允许访问,否则出现 403。
如果当前主体具有指定的角色,则返回 true。
底层源码
Spring Security_第8张图片

给用户添加角色
Spring Security_第9张图片
修改配置文件
Spring Security_第10张图片
修改配置文件:
== 注意配置文件中不需要添加”ROLE_“,因为上述的底层代码会自动添加与之进行匹配。==

3.4.4 hasAnyRole

表示用户具备任何一个条件都可以访问。
给用户添加角色:
Spring Security_第11张图片

3.5自定义403页面

  1. 在static下面创建一个名为 unauth.html的文件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>对不起您没有该页面的授权</h1>
</body>
</html>
  1. 在SpringSecurity中添加403的路径
    Spring Security_第12张图片
 @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling().accessDeniedPage("/unauth.html");
        http.formLogin() //自定义自己编写的登录页面
            .loginPage("/login.html") //登录页面设置
            .loginProcessingUrl("/user/login") //登录访问路径  框架以及写好
            .defaultSuccessUrl("/text/index").permitAll() //登录成功之后页面跳转
            .and().authorizeRequests()
                .antMatchers("/","/text/hollow","/user/login").permitAll()
                //设置当前用户,只有具备admins才可以访问这个路径
                //hasAuthority
                .antMatchers("/text/index").hasAuthority("admins")
                //hasAnyAuthority
//                .antMatchers("/text/index").hasAnyAuthority("admins","manager")
                //        hasRole
//                .antMatchers("/text/index").hasRole("admins")
                // hasAnyRole
//                .antMatchers().hasAnyRole("admins","manager")
            .anyRequest().authenticated()
            .and().csrf().disable();//关闭csrf保护

    }

测试
Spring Security_第13张图片

3.6 注解的使用

3.6.1 @Secured

判断是否具有角色,用户具有某个角色可以访问方法,另外需要注意的是这里匹配的字符串需要添加前缀“ROLE_“。

  1. 启动类(配置类)开启注解
    @EnableGlobalMethodSecurity(securedEnabled = true)
  2. 在controller的方法上使用注解,设置角色
  @GetMapping("/update")
    @Secured({"ROLE_sale","ROLE_manager"})//角色为"ROLE_sale","ROLE_manager"才能访问
    public String update()
    {
        return "hollow update";
    }
  1. 在userDetailService设置角色
  2. 测试

3.6.2@PreAuthorize

@PreAuthorize:注解适合进入方法前的权限验证, @PreAuthorize 可以将登录用户的roles/permissions 参数传到方法中。

  1. 添加注解@EnableGlobalMethodSecurity(prePostEnabled = true)
  2. controller
    @GetMapping("/update")
//    @Secured({"ROLE_sale","ROLE_manager","sale"}) //角色为"ROLE_sale","ROLE_manager"才能访问
    @PreAuthorize("hasAuthority('admin')") //角色为admin才能访问
    public String update()
    {
        return "hollow update";
    }

3.6.3 @PostAuthorize

@PostAuthorize 注解使用并不多,在方法执行后再进行权限验证,适合验证带有返回值
的权限.

  1. 先开启注解功能:
    @EnableGlobalMethodSecurity(prePostEnabled = true)
  2. controller
    @GetMapping("/update")
//    @Secured({"ROLE_sale","ROLE_manager","sale"})
//    @PreAuthorize("hasAuthority('admin')")
    @PostAuthorize("hasAnyAuthority('admins')") //当前用户即使没有admins的权限也会执行update函数,即输出1
    public String update()
    {
        System.out.println(1);
        return "hollow update";
    }

3.6.4@PostFilter

@PostFilter :对方法返回的数据进行过滤,权限验证之后对数据进行过滤 留下用户名是 admin1 的数据
表达式中的 filterObject 引用的是方法返回值 List 中的某一个元素

 @RequestMapping("getAll")
    @PostFilter("filterObject.username == 'admin1'")
    @ResponseBody
    public List<Users> getAllUser(){
        ArrayList<Users> list = new ArrayList<>();
        list.add(new Users(1,"admin1","6666"));
        list.add(new Users(2,"admin2","888"));
        for(Users users:list)
        {
            System.out.println(users);
        }
        return list;
    }

3.6.5 @PreFilter

@PreFilter: 进入控制器之前对数据进行过滤

@RequestMapping("getTestPreFilter")
@PreFilter(value = "filterObject.id%2==0") //用户的id可以被2整除
@ResponseBody
public List<UserInfo> getTestPreFilter(@RequestBody List<UserInfo> 
list){
 list.forEach(t-> {
 System.out.println(t.getId()+"\t"+t.getUsername());
 });
return list;
}

3.7 用户注销

  1. 在配置类添加退出配置
    Spring Security_第14张图片
   @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.logout().logoutUrl("/logout")//退出的地址
                .logoutUrl("/text/hollow").permitAll();//退出成功返回的地址
        http.exceptionHandling().accessDeniedPage("/unauth.html");
        http.formLogin() //自定义自己编写的登录页面
            .loginPage("/login.html") //登录页面设置
            .loginProcessingUrl("/user/login") //登录访问路径  框架以及写好
            .defaultSuccessUrl("/text/index").permitAll() //登录成功之后页面跳转
            .and().authorizeRequests()
                .antMatchers("/","/text/hollow","/user/login").permitAll()
                //设置当前用户,只有具备admins才可以访问这个路径
                //hasAuthority
                .antMatchers("/text/index").hasAuthority("admins")
                //hasAnyAuthority
//                .antMatchers("/text/index").hasAnyAuthority("admins","manager")
                //        hasRole
//                .antMatchers("/text/index").hasRole("admins")
                // hasAnyRole
//                .antMatchers().hasAnyRole("admins","manager")
            .anyRequest().authenticated()
            .and().csrf().disable();//关闭csrf保护

    }
  1. 测试
  • 修改配置类,登录成之后跳转到成功页面
    Spring Security_第15张图片

  • 在成功页面添加超链接,设置退出路径
    编写一个名为success的HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
 登录成功
<a href="/logout">退出</a>
</body>
</html>
  • 在登录成功之后,在成功页面点击退出,在访问其他conroller不能进行访问

3.8 基于数据库在自动登录

3.8.1 实现过程

Spring Security_第16张图片

具体流程
Spring Security_第17张图片

3.8.2 具体实现

  1. 建表(固定的)
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;
  1. 配置类,注入数据源,配置操作数据的对象
  @Autowired
    private DataSource dataSource;

    @Bean
    public PersistentTokenRepository persistentTokenRepository()
    {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
       // jdbcTokenRepository.setCreateTableOnStartup(true);//启动时自动创建表
        return jdbcTokenRepository;
    }

Spring Security_第18张图片
3. 配置类中配置自动登录
在这里插入图片描述

   @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.logout().logoutUrl("/logout")//退出的地址
                .logoutSuccessUrl("/text/hollow").permitAll();//退出成功返回的地址
        http.exceptionHandling().accessDeniedPage("/unauth.html");
        http.formLogin() //自定义自己编写的登录页面
            .loginPage("/login.html") //登录页面设置
            .loginProcessingUrl("/user/login") //登录访问路径  框架以及写好
            .defaultSuccessUrl("/success.html").permitAll() //登录成功之后页面跳转
            .and().authorizeRequests()
                .antMatchers("/","/text/hollow","/user/login").permitAll()
                //设置当前用户,只有具备admins才可以访问这个路径
                //hasAuthority
                .antMatchers("/text/index").hasAuthority("admins")
                //hasAnyAuthority
//                .antMatchers("/text/index").hasAnyAuthority("admins","manager")
                //        hasRole
//                .antMatchers("/text/index").hasRole("admins")
                // hasAnyRole
//                .antMatchers().hasAnyRole("admins","manager")
            .anyRequest().authenticated()
            .and().rememberMe().tokenRepository(persistentTokenRepository()) //操作数据库的对象
            .tokenValiditySeconds(60)//设置有效时长(秒为单位)
            .userDetailsService(userDetailsService())//userDetailsService操作底层数据库
            .and().csrf().disable();//关闭csrf保护

    }
  1. 在登录页面添加复选框
      <input type="checkbox" name="remember-me"/>自动登录
      <br>

Spring Security_第19张图片

3.9 CSRF

3.9.1 CSRF 理解

跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法。跟跨网站脚本**(XSS)**相比,XSS利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。
跨站请求攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并运行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去运行。这利用了 web 中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。从 Spring Security 4.0 开始,默认情况下会启用 CSRF 保护,以防止 CSRF 攻击应用程序,Spring Security CSRF 会针对 PATCH,POST,PUT 和 DELETE 方法进行防护。

  • 案例
    在登录页面添加一个隐藏域:
<input 
type="hidden"th:if="${_csrf}!=null"th:value="${_csrf.token}"name="_csrf"/>

关闭安全配置的类中的 csrf

// http.csrf().disable();

Spring Security_第20张图片

4.SpringSecurity微服务权限方案

4.1 什么是微服务

4.1.1、微服务由来

微服务最早由 Martin Fowler 与 James Lewis 于 2014 年共同提出,微服务架构风格是一种使用一套小服务来开发单个应用的方式途径,每个服务运行在自己的进程中,并使用轻量级机制通信,通常是 HTTP API,这些服务基于业务能力构建,并能够通过自动化部署机制来独立部署,这些服务使用不同的编程语言实现,以及不同数据存储技术,并保持最低限度的集中式管理。

4.1. 2、微服务优势

  1. 微服务每个模块就相当于一个单独的项目,代码量明显减少,遇到问题也相对来说比较好解决。
  2. 微服务每个模块都可以使用不同的存储方式(比如有的用 redis,有的用 mysql等),数据库也是单个模块对应自己的数据库。
  3. 微服务每个模块都可以使用不同的开发技术,开发模式更灵活。

4.1.3、微服务本质

  1. 微服务,关键其实不仅仅是微服务本身,而是系统要提供一套基础的架构,这种架构使得微服务可以独立的部署、运行、升级,不仅如此,这个系统架构还让微服务与微服务之间在结构上“松耦合”,而在功能上则表现为一个统一的整体。这种所谓的“统一的整体”表现出来的是统一风格的界面,统一的权限管理,统一的安全策略,统一的上线过程,统一的日志和审计方法,统一的调度方式,统一的访问入口等等。
  2. 微服务的目的是有效的拆分应用,实现敏捷开发和部署。

4.2 微服务认证与授权实现思路

4.2.1、认证授权过程分析

  1. 如果是基于 Session,那么 Spring-security 会对 cookie 里的 sessionid 进行解析,找
    到服务器存储的 session 信息,然后判断当前用户是否符合请求的要求。
  2. 如果是 token,则是解析出 token,然后将当前请求加入到 Spring-security 管理的权限
    信息中去

Spring Security_第21张图片
如果系统的模块众多,每个模块都需要进行授权与认证,所以我们选择基于 token 的形式进行授权与认证,用户根据用户名密码认证成功,然后获取当前用户角色的一系列权限值,并以用户名为 key,权限列表为 value 的形式存入 redis 缓存中,根据用户名相关信息生成 token 返回,浏览器将 token 记录到 cookie 中,每次调用 api 接口都默认将 token 携带到 header 请求头中,Spring-security 解析 header 头获取 token 信息,解析 token 获取当前用户名,根据用户名就可以从 redis 中获取权限列表,这样 Spring-security 就能够判断当前请求是否有权限访问

5.权限认证小案例

5.1 微服务权限管理案例的主要实现功能

  1. 登录(认证)
  2. 添加角色
  3. 为角色分配菜单
  4. 添加用户
  5. 为用户分配角色

5.2.权限管理数据模型

Spring Security_第22张图片
数据库

-- ----------------------------
-- 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', '全部数据', '0', null, null, null, null, null, '0', '2019-11-15 17:13:06', '2019-11-15 17:13:06');
INSERT INTO `acl_permission` VALUES ('1195268474480156673', '1', '权限管理', '1', null, '/acl', 'Layout', null, null, '0', '2019-11-15 17:13:06', '2019-11-18 13:54:25');
INSERT INTO `acl_permission` VALUES ('1195268616021139457', '1195268474480156673', '用户管理', '1', null, 'user/list', '/acl/user/list', null, null, '0', '2019-11-15 17:13:40', '2019-11-18 13:53:12');
INSERT INTO `acl_permission` VALUES ('1195268788138598401', '1195268474480156673', '角色管理', '1', null, 'role/list', '/acl/role/list', null, null, '0', '2019-11-15 17:14:21', '2019-11-15 17:14:21');
INSERT INTO `acl_permission` VALUES ('1195268893830864898', '1195268474480156673', '菜单管理', '1', null, 'menu/list', '/acl/menu/list', null, null, '0', '2019-11-15 17:14:46', '2019-11-15 17:14:46');
INSERT INTO `acl_permission` VALUES ('1195269143060602882', '1195268616021139457', '查看', '2', 'user.list', '', '', null, null, '0', '2019-11-15 17:15:45', '2019-11-17 21:57:16');
INSERT INTO `acl_permission` VALUES ('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');
INSERT INTO `acl_permission` VALUES ('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');
INSERT INTO `acl_permission` VALUES ('1195269547269873666', '1195268616021139457', '删除', '2', 'user.remove', '', '', null, null, '0', '2019-11-15 17:17:22', '2019-11-15 17:17:22');
INSERT INTO `acl_permission` VALUES ('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');
INSERT INTO `acl_permission` VALUES ('1195269903542444034', '1195268788138598401', '查看', '2', 'role.list', '', '', null, null, '0', '2019-11-15 17:18:47', '2019-11-15 17:18:47');
INSERT INTO `acl_permission` VALUES ('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');
INSERT INTO `acl_permission` VALUES ('1195270442602782721', '1195268788138598401', '删除', '2', 'role.remove', '', '', null, null, '0', '2019-11-15 17:20:55', '2019-11-15 17:20:55');
INSERT INTO `acl_permission` VALUES ('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');
INSERT INTO `acl_permission` VALUES ('1195270744097742849', '1195268893830864898', '查看', '2', 'permission.list', '', '', null, null, '0', '2019-11-15 17:22:07', '2019-11-15 17:22:07');
INSERT INTO `acl_permission` VALUES ('1195270810560684034', '1195268893830864898', '添加', '2', 'permission.add', '', '', null, null, '0', '2019-11-15 17:22:23', '2019-11-15 17:22:23');
INSERT INTO `acl_permission` VALUES ('1195270862100291586', '1195268893830864898', '修改', '2', 'permission.update', '', '', null, null, '0', '2019-11-15 17:22:35', '2019-11-15 17:22:35');
INSERT INTO `acl_permission` VALUES ('1195270887933009922', '1195268893830864898', '删除', '2', 'permission.remove', '', '', null, null, '0', '2019-11-15 17:22:41', '2019-11-15 17:22:41');
INSERT INTO `acl_permission` VALUES ('1195349439240048642', '1', '讲师管理', '1', null, '/edu/teacher', 'Layout', null, null, '0', '2019-11-15 22:34:49', '2019-11-15 22:34:49');
INSERT INTO `acl_permission` VALUES ('1195349699995734017', '1195349439240048642', '讲师列表', '1', null, 'list', '/edu/teacher/list', null, null, '0', '2019-11-15 22:35:52', '2019-11-15 22:35:52');
INSERT INTO `acl_permission` VALUES ('1195349810561781761', '1195349439240048642', '添加讲师', '1', null, 'create', '/edu/teacher/form', null, null, '0', '2019-11-15 22:36:18', '2019-11-15 22:36:18');
INSERT INTO `acl_permission` VALUES ('1195349876252971010', '1195349810561781761', '添加', '2', 'teacher.add', '', '', null, null, '0', '2019-11-15 22:36:34', '2019-11-15 22:36:34');
INSERT INTO `acl_permission` VALUES ('1195349979797753857', '1195349699995734017', '查看', '2', 'teacher.list', '', '', null, null, '0', '2019-11-15 22:36:58', '2019-11-15 22:36:58');
INSERT INTO `acl_permission` VALUES ('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');
INSERT INTO `acl_permission` VALUES ('1195350188359520258', '1195349699995734017', '删除', '2', 'teacher.remove', '', '', null, null, '0', '2019-11-15 22:37:48', '2019-11-15 22:37:48');
INSERT INTO `acl_permission` VALUES ('1195350299365969922', '1', '课程分类', '1', null, '/edu/subject', 'Layout', null, null, '0', '2019-11-15 22:38:15', '2019-11-15 22:38:15');
INSERT INTO `acl_permission` VALUES ('1195350397751758850', '1195350299365969922', '课程分类列表', '1', null, 'list', '/edu/subject/list', null, null, '0', '2019-11-15 22:38:38', '2019-11-15 22:38:38');
INSERT INTO `acl_permission` VALUES ('1195350500512206850', '1195350299365969922', '导入课程分类', '1', null, 'import', '/edu/subject/import', null, null, '0', '2019-11-15 22:39:03', '2019-11-15 22:39:03');
INSERT INTO `acl_permission` VALUES ('1195350612172967938', '1195350397751758850', '查看', '2', 'subject.list', '', '', null, null, '0', '2019-11-15 22:39:29', '2019-11-15 22:39:29');
INSERT INTO `acl_permission` VALUES ('1195350687590748161', '1195350500512206850', '导入', '2', 'subject.import', '', '', null, null, '0', '2019-11-15 22:39:47', '2019-11-15 22:39:47');
INSERT INTO `acl_permission` VALUES ('1195350831744782337', '1', '课程管理', '1', null, '/edu/course', 'Layout', null, null, '0', '2019-11-15 22:40:21', '2019-11-15 22:40:21');
INSERT INTO `acl_permission` VALUES ('1195350919074385921', '1195350831744782337', '课程列表', '1', null, 'list', '/edu/course/list', null, null, '0', '2019-11-15 22:40:42', '2019-11-15 22:40:42');
INSERT INTO `acl_permission` VALUES ('1195351020463296513', '1195350831744782337', '发布课程', '1', null, 'info', '/edu/course/info', null, null, '0', '2019-11-15 22:41:06', '2019-11-15 22:41:06');
INSERT INTO `acl_permission` VALUES ('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');
INSERT INTO `acl_permission` VALUES ('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');
INSERT INTO `acl_permission` VALUES ('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');
INSERT INTO `acl_permission` VALUES ('1195351862889254913', '1', '统计分析', '1', null, '/statistics/daily', 'Layout', null, null, '0', '2019-11-15 22:44:27', '2019-11-15 22:44:27');
INSERT INTO `acl_permission` VALUES ('1195351968841568257', '1195351862889254913', '生成统计', '1', null, 'create', '/statistics/daily/create', null, null, '0', '2019-11-15 22:44:53', '2019-11-15 22:44:53');
INSERT INTO `acl_permission` VALUES ('1195352054917074946', '1195351862889254913', '统计图表', '1', null, 'chart', '/statistics/daily/chart', null, null, '0', '2019-11-15 22:45:13', '2019-11-15 22:45:13');
INSERT INTO `acl_permission` VALUES ('1195352127734386690', '1195352054917074946', '查看', '2', 'daily.list', '', '', null, null, '0', '2019-11-15 22:45:30', '2019-11-15 22:45:30');
INSERT INTO `acl_permission` VALUES ('1195352215768633346', '1195351968841568257', '生成', '2', 'daily.add', '', '', null, null, '0', '2019-11-15 22:45:51', '2019-11-15 22:45:51');
INSERT INTO `acl_permission` VALUES ('1195352547621965825', '1', 'CMS管理', '1', null, '/cms', 'Layout', null, null, '0', '2019-11-15 22:47:11', '2019-11-18 10:51:46');
INSERT INTO `acl_permission` VALUES ('1195352856645701633', '1195353513549205505', '查看', '2', 'banner.list', '', null, null, null, '0', '2019-11-15 22:48:24', '2019-11-15 22:48:24');
INSERT INTO `acl_permission` VALUES ('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');
INSERT INTO `acl_permission` VALUES ('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');
INSERT INTO `acl_permission` VALUES ('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');
INSERT INTO `acl_permission` VALUES ('1195353672110673921', '1195353513549205505', '删除', '2', 'banner.remove', '', '', null, null, '0', '2019-11-15 22:51:39', '2019-11-15 22:51:39');
INSERT INTO `acl_permission` VALUES ('1195354076890370050', '1', '订单管理', '1', null, '/order', 'Layout', null, null, '0', '2019-11-15 22:53:15', '2019-11-15 22:53:15');
INSERT INTO `acl_permission` VALUES ('1195354153482555393', '1195354076890370050', '订单列表', '1', null, 'list', '/order/list', null, null, '0', '2019-11-15 22:53:33', '2019-11-15 22:53:58');
INSERT INTO `acl_permission` VALUES ('1195354315093282817', '1195354153482555393', '查看', '2', 'order.list', '', '', null, null, '0', '2019-11-15 22:54:12', '2019-11-15 22:54:12');
INSERT INTO `acl_permission` VALUES ('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');

-- ----------------------------
-- 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', '普通管理员', null, null, '0', '2019-11-11 13:09:32', '2019-11-18 10:27:18');
INSERT INTO `acl_role` VALUES ('1193757683205607426', '课程管理员', null, null, '0', '2019-11-11 13:09:45', '2019-11-18 10:25:44');
INSERT INTO `acl_role` VALUES ('1196300996034977794', 'test', null, null, '0', '2019-11-18 13:35:58', '2019-11-18 13:35:58');




SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- 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 ('1196301979754455041', '1', '1', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301979792203778', '1', '1195268474480156673', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301979821563906', '1', '1195268616021139457', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301979842535426', '1', '1195269143060602882', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301979855118338', '1', '1195269295926206466', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301979880284161', '1', '1195269473479483394', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301979913838593', '1', '1195269547269873666', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301979926421506', '1', '1196301740985311234', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301979951587330', '1', '1195268788138598401', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980014501889', '1', '1195269821262782465', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980035473410', '1', '1195269903542444034', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980052250626', '1', '1195270037005197313', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980077416450', '1', '1195270442602782721', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980094193665', '1', '1195270621548568578', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980119359489', '1', '1195268893830864898', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980136136706', '1', '1195270744097742849', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980249382913', '1', '1195270810560684034', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980270354434', '1', '1195270862100291586', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980287131649', '1', '1195270887933009922', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980303908866', '1', '1195349439240048642', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980320686082', '1', '1195349699995734017', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980345851905', '1', '1195349979797753857', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980362629121', '1', '1195350117270261762', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980383600641', '1', '1195350188359520258', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980408766465', '1', '1195349810561781761', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980421349378', '1', '1195349876252971010', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980438126593', '1', '1195350299365969922', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980450709506', '1', '1195350397751758850', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980501041153', '1', '1195350612172967938', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980517818370', '1', '1195350500512206850', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980538789889', '1', '1195350687590748161', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980622675970', '1', '1195350831744782337', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980639453186', '1', '1195350919074385921', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980660424705', '1', '1195351159672246274', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980677201922', '1', '1195351326706208770', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980698173441', '1', '1195351566221938690', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980714950658', '1', '1195351020463296513', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980723339266', '1', '1195351862889254913', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980744310786', '1', '1195351968841568257', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980761088001', '1', '1195352215768633346', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980777865217', '1', '1195352054917074946', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980794642434', '1', '1195352127734386690', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980811419650', '1', '1195352547621965825', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980828196865', '1', '1195353513549205505', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980844974082', '1', '1195352856645701633', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980861751298', '1', '1195352909401657346', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980886917122', '1', '1195353051395624961', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980928860162', '1', '1195353672110673921', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980954025986', '1', '1195354076890370050', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980970803201', '1', '1195354153482555393', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196301980987580418', '1', '1195354315093282817', '1', '2019-11-18 13:39:53', '2019-11-18 13:39:53');
INSERT INTO `acl_role_permission` VALUES ('1196305293070077953', '1', '1', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293099438081', '1', '1195268474480156673', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293120409602', '1', '1195268616021139457', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293153964034', '1', '1195269143060602882', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293183324162', '1', '1195269295926206466', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293212684290', '1', '1195269473479483394', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293237850114', '1', '1195269547269873666', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293271404545', '1', '1196301740985311234', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293485314049', '1', '1195268788138598401', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293506285569', '1', '1195269821262782465', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293527257089', '1', '1195269903542444034', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293552422914', '1', '1195270037005197313', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293565005825', '1', '1195270442602782721', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293594365954', '1', '1195270621548568578', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293611143169', '1', '1195268893830864898', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293627920385', '1', '1195270744097742849', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293657280513', '1', '1195349439240048642', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293674057729', '1', '1195349699995734017', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293690834946', '1', '1195349979797753857', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293716000770', '1', '1195350117270261762', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293736972290', '1', '1195350188359520258', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293749555202', '1', '1195349810561781761', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293766332417', '1', '1195349876252971010', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293795692546', '1', '1195350299365969922', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293812469762', '1', '1195350397751758850', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293837635586', '1', '1195350612172967938', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293858607106', '1', '1195350500512206850', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293875384322', '1', '1195350687590748161', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293892161538', '1', '1195350831744782337', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293950881794', '1', '1195350919074385921', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305293976047617', '1', '1195351159672246274', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305294127042561', '1', '1195351326706208770', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305294156402690', '1', '1195351566221938690', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305294177374209', '1', '1195351862889254913', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305294194151425', '1', '1195351968841568257', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305294223511554', '1', '1195352215768633346', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305294240288770', '1', '1195352054917074946', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305294248677377', '1', '1195352127734386690', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305294248677378', '1', '1195352547621965825', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305294319980546', '1', '1195353513549205505', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305294319980547', '1', '1195352856645701633', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305294319980548', '1', '1195352909401657346', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305294378700802', '1', '1195353051395624961', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305294378700803', '1', '1195353672110673921', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305294458392577', '1', '1195354076890370050', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305294483558402', '1', '1195354153482555393', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305294500335618', '1', '1195354315093282817', '1', '2019-11-18 13:53:03', '2019-11-18 13:53:03');
INSERT INTO `acl_role_permission` VALUES ('1196305566656139266', '1', '1', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305566689693698', '1', '1195268474480156673', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305566706470913', '1', '1195268616021139457', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305566740025346', '1', '1195269143060602882', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305566756802561', '1', '1195269295926206466', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305566781968385', '1', '1195269473479483394', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305566811328514', '1', '1195269547269873666', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305566828105730', '1', '1196301740985311234', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305566853271554', '1', '1195268788138598401', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305566878437378', '1', '1195269821262782465', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305566895214593', '1', '1195269903542444034', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305566916186113', '1', '1195270037005197313', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305566949740546', '1', '1195270442602782721', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305566966517761', '1', '1195270621548568578', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305566991683585', '1', '1195268893830864898', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567012655106', '1', '1195270744097742849', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567029432322', '1', '1195270810560684034', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567042015233', '1', '1195270862100291586', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567100735490', '1', '1195270887933009922', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567117512705', '1', '1195349439240048642', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567142678530', '1', '1195349699995734017', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567155261442', '1', '1195349979797753857', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567172038658', '1', '1195350117270261762', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567188815873', '1', '1195350188359520258', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567218176001', '1', '1195349810561781761', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567234953217', '1', '1195349876252971010', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567251730434', '1', '1195350299365969922', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567272701954', '1', '1195350397751758850', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567289479170', '1', '1195350612172967938', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567310450690', '1', '1195350500512206850', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567327227905', '1', '1195350687590748161', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567448862722', '1', '1195350831744782337', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567478222850', '1', '1195350919074385921', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567495000065', '1', '1195351159672246274', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567520165889', '1', '1195351326706208770', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567541137409', '1', '1195351566221938690', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567570497538', '1', '1195351862889254913', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567587274754', '1', '1195351968841568257', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567604051970', '1', '1195352215768633346', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567633412098', '1', '1195352054917074946', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567683743745', '1', '1195352127734386690', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567721492481', '1', '1195352547621965825', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567742464002', '1', '1195353513549205505', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567771824129', '1', '1195352856645701633', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567792795650', '1', '1195352909401657346', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567809572866', '1', '1195353051395624961', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567843127298', '1', '1195353672110673921', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567868293122', '1', '1195354076890370050', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567885070338', '1', '1195354153482555393', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196305567910236162', '1', '1195354315093282817', '1', '2019-11-18 13:54:08', '2019-11-18 13:54:08');
INSERT INTO `acl_role_permission` VALUES ('1196312702601695234', '1', '1', '0', '2019-11-18 14:22:29', '2019-11-18 14:22:29');
INSERT INTO `acl_role_permission` VALUES ('1196312702652026881', '1', '1195268474480156673', '0', '2019-11-18 14:22:29', '2019-11-18 14:22:29');
INSERT INTO `acl_role_permission` VALUES ('1196312702668804098', '1', '1195268616021139457', '0', '2019-11-18 14:22:29', '2019-11-18 14:22:29');
INSERT INTO `acl_role_permission` VALUES ('1196312702698164226', '1', '1195269143060602882', '0', '2019-11-18 14:22:29', '2019-11-18 14:22:29');
INSERT INTO `acl_role_permission` VALUES ('1196312702723330049', '1', '1195269295926206466', '0', '2019-11-18 14:22:29', '2019-11-18 14:22:29');
INSERT INTO `acl_role_permission` VALUES ('1196312702744301569', '1', '1195269473479483394', '0', '2019-11-18 14:22:29', '2019-11-18 14:22:29');
INSERT INTO `acl_role_permission` VALUES ('1196312702765273089', '1', '1195269547269873666', '0', '2019-11-18 14:22:29', '2019-11-18 14:22:29');
INSERT INTO `acl_role_permission` VALUES ('1196312702790438913', '1', '1196301740985311234', '0', '2019-11-18 14:22:29', '2019-11-18 14:22:29');
INSERT INTO `acl_role_permission` VALUES ('1196312702945628161', '1', '1195268788138598401', '0', '2019-11-18 14:22:29', '2019-11-18 14:22:29');
INSERT INTO `acl_role_permission` VALUES ('1196312702970793985', '1', '1195269821262782465', '0', '2019-11-18 14:22:29', '2019-11-18 14:22:29');
INSERT INTO `acl_role_permission` VALUES ('1196312703000154114', '1', '1195269903542444034', '0', '2019-11-18 14:22:29', '2019-11-18 14:22:29');
INSERT INTO `acl_role_permission` VALUES ('1196312703025319938', '1', '1195270037005197313', '0', '2019-11-18 14:22:29', '2019-11-18 14:22:29');
INSERT INTO `acl_role_permission` VALUES ('1196312703046291458', '1', '1195270442602782721', '0', '2019-11-18 14:22:29', '2019-11-18 14:22:29');
INSERT INTO `acl_role_permission` VALUES ('1196312703063068673', '1', '1195270621548568578', '0', '2019-11-18 14:22:29', '2019-11-18 14:22:29');
INSERT INTO `acl_role_permission` VALUES ('1196312703084040193', '1', '1195268893830864898', '0', '2019-11-18 14:22:29', '2019-11-18 14:22:29');
INSERT INTO `acl_role_permission` VALUES ('1196312703113400321', '1', '1195270744097742849', '0', '2019-11-18 14:22:29', '2019-11-18 14:22:29');
INSERT INTO `acl_role_permission` VALUES ('1196312703134371842', '1', '1195270810560684034', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703159537665', '1', '1195270862100291586', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703184703490', '1', '1195270887933009922', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703209869313', '1', '1195349439240048642', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703230840834', '1', '1195349699995734017', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703251812354', '1', '1195349979797753857', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703272783873', '1', '1195350117270261762', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703293755394', '1', '1195350188359520258', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703327309826', '1', '1195349810561781761', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703348281345', '1', '1195349876252971010', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703365058561', '1', '1195350299365969922', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703386030082', '1', '1195350397751758850', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703440556034', '1', '1195350612172967938', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703486693378', '1', '1195350500512206850', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703511859202', '1', '1195350687590748161', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703654465537', '1', '1195350831744782337', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703683825665', '1', '1195350919074385921', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703700602882', '1', '1195351159672246274', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703717380098', '1', '1195351326706208770', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703738351618', '1', '1195351566221938690', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703759323137', '1', '1195351020463296513', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703776100353', '1', '1195351862889254913', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703792877570', '1', '1195351968841568257', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703830626305', '1', '1195352215768633346', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703843209217', '1', '1195352054917074946', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703868375041', '1', '1195352127734386690', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703889346561', '1', '1195352547621965825', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703901929473', '1', '1195353513549205505', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703918706689', '1', '1195352856645701633', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703952261121', '1', '1195352909401657346', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703973232642', '1', '1195353051395624961', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312703990009857', '1', '1195353672110673921', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312704048730114', '1', '1195354076890370050', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312704069701633', '1', '1195354153482555393', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');
INSERT INTO `acl_role_permission` VALUES ('1196312704094867457', '1', '1195354315093282817', '0', '2019-11-18 14:22:30', '2019-11-18 14:22:30');




-- ----------------------------
-- 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(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='用户表';

-- ----------------------------
-- Records of 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');
INSERT INTO `acl_user` VALUES ('2', 'test', '96e79218965eb72c92a549dd5a330112', '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', '2', '0', '2019-11-11 13:09:53', '2019-11-11 13:09:53');

5.3相关技术的介绍

  1. maven:创建父工程:管理项目依赖管理,创建子工程,使用具体依赖
  2. SpringBoot
  3. MyBatisPlus
  4. SpringCloud:GateWay :网关 注册中心 nacos
  5. 其他技术 Jwt Swagger Redis

5.4 搭建环境

  1. 创建一个名为acl_parent的父工程,打包方式、为pom
  2. 在父工程下的子模块
    1. common
    service_base:工具类
    spring_security:权限控制
    2. infrastructure
    getway:网关
    3. service
    service-acl :权限管理微服务模块
    Spring Security_第23张图片
  3. 在acl_parent中引入依赖
<properties>
        <java.version>1.8java.version>
        <mybatis-plus.version>3.0.5mybatis-plus.version>
        <velocity.version>2.0velocity.version>
        <swagger.version>2.7.0swagger.version>
        <jwt.version>0.7.0jwt.version>
        <fastjson.version>1.2.28fastjson.version>
        <gson.version>2.8.2gson.version>
        <json.version>20170516json.version>
        <cloud-alibaba.version>0.2.2.RELEASEcloud-alibaba.version>
    properties>
    <dependencyManagement>
        <dependencies>
            
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-dependenciesartifactId>
                <version>Hoxton.RELEASEversion>
                <type>pomtype>
                <scope>importscope>
            dependency>

            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-alibaba-dependenciesartifactId>
                <version>${cloud-alibaba.version}version>
                <type>pomtype>
                <scope>importscope>
            dependency>
            
            <dependency>
                <groupId>com.baomidougroupId>
                <artifactId>mybatis-plus-boot-starterartifactId>
                <version>${mybatis-plus.version}version>
            dependency>

            
            <dependency>
                <groupId>org.apache.velocitygroupId>
                <artifactId>velocity-engine-coreartifactId>
                <version>${velocity.version}version>
            dependency>

            <dependency>
                <groupId>com.google.code.gsongroupId>
                <artifactId>gsonartifactId>
                <version>${gson.version}version>
            dependency>
            
            <dependency>
                <groupId>io.springfoxgroupId>
                <artifactId>springfox-swagger2artifactId>
                <version>${swagger.version}version>
            dependency>
            
            <dependency>
                <groupId>io.springfoxgroupId>
                <artifactId>springfox-swagger-uiartifactId>
                <version>${swagger.version}version>
            dependency>
            
            <dependency>
                <groupId>io.jsonwebtokengroupId>
                <artifactId>jjwtartifactId>
                <version>${jwt.version}version>
            dependency>
            <dependency>
                <groupId>com.alibabagroupId>
                <artifactId>fastjsonartifactId>
                <version>${fastjson.version}version>
            dependency>
            <dependency>
                <groupId>org.jsongroupId>
                <artifactId>jsonartifactId>
                <version>${json.version}version>
            dependency>
        dependencies>
    dependencyManagement>
  1. common中的依赖
   <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
            <scope>provided scope>
        dependency>

        
        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-boot-starterartifactId>
            <scope>provided scope>
        dependency>

        
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <scope>provided scope>
        dependency>
        
        <dependency>
            <groupId>io.springfoxgroupId>
            <artifactId>springfox-swagger2artifactId>
            <scope>provided scope>
        dependency>
        <dependency>
            <groupId>io.springfoxgroupId>
            <artifactId>springfox-swagger-uiartifactId>
            <scope>provided scope>
        dependency>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-redisartifactId>
        dependency>

        
        <dependency>
            <groupId>org.apache.commonsgroupId>
            <artifactId>commons-pool2artifactId>
            <version>2.6.0version>
        dependency>
    dependencies>
  1. springSecurity中的依赖
    <dependencies>
        <dependency>
            <groupId>com.blbgroupId>
            <artifactId>service_baseartifactId>
            <version>0.0.1-SNAPSHOTversion>
        dependency>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-securityartifactId>
        dependency>

        <dependency>
            <groupId>io.jsonwebtokengroupId>
            <artifactId>jjwtartifactId>
        dependency>
    dependencies>
  1. api_getway中的依赖
    <dependencies>
        <dependency>
            <groupId>com.blbgroupId>
            <artifactId>service_baseartifactId>
            <version>0.0.1-SNAPSHOTversion>
        dependency>

        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-gatewayartifactId>
        dependency>

        
        <dependency>
            <groupId>com.google.code.gsongroupId>
            <artifactId>gsonartifactId>
        dependency>

        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-openfeignartifactId>
        dependency>
    dependencies>
  1. service中的依赖
<dependencies>

        <dependency>
            <groupId>com.blbgroupId>
            <artifactId>service_baseartifactId>
            <version>0.0.1-SNAPSHOTversion>
        dependency>

        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
        dependency>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-openfeignartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

        
        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-boot-starterartifactId>
        dependency>
        
        <dependency>
            <groupId>io.springfoxgroupId>
            <artifactId>springfox-swagger2artifactId>
        dependency>
        <dependency>
            <groupId>io.springfoxgroupId>
            <artifactId>springfox-swagger-uiartifactId>
        dependency>
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
        dependency>

        
        <dependency>
            <groupId>org.apache.velocitygroupId>
            <artifactId>velocity-engine-coreartifactId>
        dependency>


        
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
        dependency>
        
        <dependency>
            <groupId>com.google.code.gsongroupId>
            <artifactId>gsonartifactId>
        dependency>
    dependencies>
  1. service_acl中的依赖
   <dependencies>
        <dependency>
            <groupId>com.atguigugroupId>
            <artifactId>spring_securityartifactId>
            <version>0.0.1-SNAPSHOTversion>
        dependency>
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>fastjsonartifactId>
        dependency>
    dependencies>
  1. 启动redis和nacos

5.5具体代码的编写

5.5.1 编写common里面的工具类

Spring Security_第24张图片

  1. MD5 加密
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public final class MD5 {

    public static String encrypt(String strSrc) {
        try {
            char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
                    '9', 'a', 'b', 'c', 'd', 'e', 'f' };
            byte[] bytes = strSrc.getBytes();
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(bytes);
            bytes = md.digest();
            int j = bytes.length;
            char[] chars = new char[j * 2];
            int k = 0;
            for (int i = 0; i < bytes.length; i++) {
                byte b = bytes[i];
                chars[k++] = hexChars[b >>> 4 & 0xf];
                chars[k++] = hexChars[b & 0xf];
            }
            return new String(chars);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new RuntimeException("MD5加密出错!!+" + e);
        }
    }

    public static void main(String[] args) {
        System.out.println(MD5.encrypt("111111"));
    }

}
  1. 统一返回结果集
import lombok.Data;

import java.util.HashMap;
import java.util.Map;

//统一返回结果的类
@Data
public class R {

   private Boolean success;

   private Integer code;

   private String message;

   private Map<String, Object> data = new HashMap<String, Object>();

   //把构造方法私有
   private R() {}

   //成功静态方法
   public static R ok() {
       R r = new R();
       r.setSuccess(true);
       r.setCode(20000);
       r.setMessage("成功");
       return r;
   }

   //失败静态方法
   public static R error() {
       R r = new R();
       r.setSuccess(false);
       r.setCode(20001);
       r.setMessage("失败");
       return r;
   }

   public R success(Boolean success){
       this.setSuccess(success);
       return this;
   }

   public R message(String message){
       this.setMessage(message);
       return this;
   }

   public R code(Integer code){
       this.setCode(code);
       return this;
   }

   public R data(String key, Object value){
       this.data.put(key, value);
       return this;
   }

   public R data(Map<String, Object> map){
       this.setData(map);
       return this;
   }
}

  1. 数据返回工具类
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class ResponseUtil {

    public static void out(HttpServletResponse response, R r) {
        ObjectMapper mapper = new ObjectMapper();
        response.setStatus(HttpStatus.OK.value());
        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        try {
            mapper.writeValue(response.getWriter(), r);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  1. redis工具类
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

@EnableCaching //开启缓存
@Configuration  //配置类
public class

RedisConfig extends CachingConfigurerSupport {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setConnectionFactory(factory);
        //key序列化方式
        template.setKeySerializer(redisSerializer);
        //value序列化
        template.setValueSerializer(jackson2JsonRedisSerializer);
        //value hashmap序列化
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        return template;
    }

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // 配置序列化(解决乱码的问题),过期时间600秒
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(600))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();
        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }
}

  1. swagger工具类
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

@EnableCaching //开启缓存
@Configuration  //配置类
public class

RedisConfig extends CachingConfigurerSupport {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setConnectionFactory(factory);
        //key序列化方式
        template.setKeySerializer(redisSerializer);
        //value序列化
        template.setValueSerializer(jackson2JsonRedisSerializer);
        //value hashmap序列化
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        return template;
    }

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // 配置序列化(解决乱码的问题),过期时间600秒
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(600))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();
        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }
}

  1. 全局异常处理工具类
import com.blb.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    //指定出现什么异常执行这个方法
    @ExceptionHandler(Exception.class)
    @ResponseBody //为了返回数据
    public R error(Exception e) {
        e.printStackTrace();
        return R.error().message("执行了全局异常处理..");
    }

    //特定异常
    @ExceptionHandler(ArithmeticException.class)
    @ResponseBody //为了返回数据
    public R error(ArithmeticException e) {
        e.printStackTrace();
        return R.error().message("执行了ArithmeticException异常处理..");
    }

    //自定义异常
    @ExceptionHandler(GuliException.class)
    @ResponseBody //为了返回数据
    public R error(GuliException e) {
        log.error(e.getMessage());
        e.printStackTrace();

        return R.error().code(e.getCode()).message(e.getMsg());
    }

}

  1. 异常工具类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor  //生成有参数构造方法
@NoArgsConstructor   //生成无参数构造
public class GuliException extends RuntimeException {
    private Integer code;//状态码
    private String msg;//异常信息
}

  1. mybatis-plus自动填充工具类
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        //属性名称,不是字段名称
        this.setFieldValByName("gmtCreate", new Date(), metaObject);
        this.setFieldValByName("gmtModified", new Date(), metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("gmtModified", new Date(), metaObject);
    }
}

5.5.2 编写springsecurity认证授权工具类和处理器

Spring Security_第25张图片

  1. 密码处理工具类
import com.blb.utils.MD5;
import org.springframework.security.crypto.password.PasswordEncoder;
@Component
public class DefaultPasswordEncoder implements PasswordEncoder {

    public DefaultPasswordEncoder()
    {
        this(-1);
    }
    public DefaultPasswordEncoder(int strength)
    {

    }

    /**
     * 加密 进行MK5加密
     * @param charSequence
     * @return
     */
    @Override
    public String encode(CharSequence charSequence) {
        return MD5.encrypt(charSequence.toString());
    }

    /**
     * 进行密码比对,看密码是否正确
     * @param charSequence 加密之前的密码
     * @param encodePassword 加密之后的密码
     * @return
     */
    @Override
    public boolean matches(CharSequence charSequence, String encodePassword) {
        return encodePassword.equals(MD5.encrypt(charSequence.toString()));
    }
}
  1. Token操作工具类
    使用jwt生成token
@Component
public class TokenManager {

    //有效时间
    private long tokenEcpriation=24*60*60*1000;

    //编码密钥
    private String tokenSignKey="123456";

    //使用jwt根据用户名生成token
    public String createToken(String username)
    {
        String token= Jwts.builder().setSubject(username)
                .setExpiration(new Date(System.currentTimeMillis()+tokenEcpriation)) //设置过期时间
                .signWith(SignatureAlgorithm.ES512,tokenSignKey).compressWith(CompressionCodecs.GZIP).compact();//密钥
        return token;
    }

    //根据token字符串得到用户信息
    public String getUserInfoFromToken(String token)
    {
        String userInfo=Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody().getSubject();
        return userInfo;
    }

    //删除token
    public void removeToken(String token){}
}
  1. 退出处理器
import com.blb.utils.R;
import com.blb.utils.ResponseUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//退出处理器
public class TokenLogoutHandler implements LogoutHandler {

    private TokenManager tokenManager;
    private RedisTemplate redisTemplate;

    private TokenLogoutHandler(TokenManager tokenManager,RedisTemplate redisTemplate)
    {
        this.tokenManager=tokenManager;
        this.redisTemplate=redisTemplate;
    }

    @Override
    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
     //从header里面获取token token不为空,移除token,从redis里面删除token
        String token = request.getHeader("token");
        if(token!=null)
        {
            //移除
            tokenManager.removeToken(token);

            //从token里面获取用户名信息
            String username = tokenManager.getUserInfoFromToken(token);
            redisTemplate.delete(username);
        }
        ResponseUtil.out(response, R.ok());
    }
}

  1. 未授权统一处理类
/**
 *
 * 未授权统一处理类
 */
public class UnauthEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        ResponseUtil.out(httpServletResponse, R.error());
    }
}
  1. 认证的过滤器
    创建一个User工具类
/**
 * @author smilecb
 * @date 2021/11/28 0028 10:08
 */
@Data
@ApiModel(description = "用户实体类")
public class User {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "微信openID")
    private String username;

    @ApiModelProperty(value = "密码")
    private String password;

    @ApiModelProperty(value = "昵称")
    private String nickName;

    @ApiModelProperty(value = "用户头像")
    private String salt;

    @ApiModelProperty(value = "用户签名")
    private String token;
}

创建一个SecurityUser工具类

@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;
        }
    }
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        for(String permissionValue : permissionValueList) {
            if(StringUtils.isEmpty(permissionValue)) continue;
            SimpleGrantedAuthority authority = new
                    SimpleGrantedAuthority(permissionValue);
            authorities.add(authority);
        }
        return authorities;
    }
    @Override
    public String getPassword() {
        return currentUserInfo.getPassword();
    }
    @Override
    public String getUsername() {
        return currentUserInfo.getUsername();
    }
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
    @Override
    public boolean isEnabled() {
        return true;
    } }

认证的过滤器

public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {

    private TokenManager tokenManager;//token的操作
    private RedisTemplate redisTemplate;//redis工具
    private AuthenticationManager authenticationManager; //权限管理工具

    public TokenLoginFilter(AuthenticationManager authenticationManager,TokenManager tokenManager,RedisTemplate redisTemplate)
    {
        this.tokenManager=tokenManager;
        this.redisTemplate=redisTemplate;
        this.authenticationManager=authenticationManager;
        this.setPostOnly(false);//关闭只用post提交
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/acl/login","POST")); //设置登录路径和提交方式
    }


    /**
     * 获取表单提交的用户名和密码
     * @param request
     * @param response
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request,
                                                HttpServletResponse response) throws AuthenticationException {
         //获取表单数据
        try {
            User user = new ObjectMapper().readValue(request.getInputStream(), User.class);
            return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(),user.getPassword(),new ArrayList<>()));
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException();
        }
    }

    /**
     * 登录成功
     * @param request
     * @param response
     * @param chain
     * @param authResult
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request,
                                            HttpServletResponse response,
                                            FilterChain chain,
                                            Authentication authResult) throws IOException, ServletException {
        //认证成功得到认证成功之后的用户信息
        SecurityUser user = (SecurityUser) authResult.getPrincipal();
        //根据用户名生成token
        String token = tokenManager.createToken(user.getCurrentUserInfo().getUsername());
        //把用户名称和用户权限列表放入redis
        redisTemplate.opsForValue().set(user.getCurrentUserInfo().getUsername(),user.getPermissionValueList());
        //返回token
        ResponseUtil.out(response, R.ok().data("token",token));
    }

    /**
     * 登录失败
     * @param request
     * @param response
     * @param failed
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request,
                                              HttpServletResponse response,
                                              AuthenticationException failed) throws IOException, ServletException {
        super.unsuccessfulAuthentication(request, response, failed);
        ResponseUtil.out(response,R.error());
    }
}

  1. 授权过滤器
//授权过滤器
public class TokenAuthFilter extends BasicAuthenticationFilter {

    private TokenManager tokenManager;

    private RedisTemplate redisTemplate;

    public TokenAuthFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
        this.tokenManager=tokenManager;
        this.redisTemplate=redisTemplate;

    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        //获取当前认证成功的用户权限信息
        UsernamePasswordAuthenticationToken authentication = getAuthentication(request);
        //判断是否有权限信息,有放在权限上下文当中
           if(authentication!=null)
        {
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        chain.doFilter(request,response);

    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request)
    {
        //从header里面获取token
        String token = request.getHeader("token");
        if(token!=null)
        {
            //从token里面获取用户名
            String username = tokenManager.getUserInfoFromToken(token);
            //从redis里面后期对应的权限列表
            List<String> permissionValueList=(List<String>)redisTemplate.opsForValue().get(username);
            Collection<GrantedAuthority> authority=new ArrayList<>();
            for(String p:permissionValueList)
            {
                SimpleGrantedAuthority grantedAuthority = new SimpleGrantedAuthority(p);
                authority.add(grantedAuthority);
            }
            return new UsernamePasswordAuthenticationToken(username,token,authority);
        }
            return null;
    }

}
  1. 编写核心配置类TokenWebSecurityConfig
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter {

    private TokenManager tokenManager;
    private RedisTemplate redisTemplate;
    private DefaultPasswordEncoder defaultPasswordEncoder;
    private UserDetailsService userDetailsService;

    @Autowired
    public TokenWebSecurityConfig(UserDetailsService userDetailsService, DefaultPasswordEncoder defaultPasswordEncoder,
                                  TokenManager tokenManager, RedisTemplate redisTemplate) {
        this.userDetailsService = userDetailsService;
        this.defaultPasswordEncoder = defaultPasswordEncoder;
        this.tokenManager = tokenManager;
        this.redisTemplate = redisTemplate;
    }

    /**
     * 配置设置
     * @param http
     * @throws Exception
     */
    //设置退出的地址和token,redis操作地址
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling()
                .authenticationEntryPoint(new UnauthEntryPoint())//没有权限访问
                .and().csrf().disable()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and().logout().logoutUrl("/admin/acl/index/logout")//退出路径
                .addLogoutHandler(new TokenLogoutHandler(tokenManager,redisTemplate)).and()
                .addFilter(new TokenLoginFilter(authenticationManager(), tokenManager, redisTemplate))  //添加登录过滤器
                .addFilter(new TokenAuthFilter(authenticationManager(),tokenManager,redisTemplate)).httpBasic(); //添加授权过滤器
    }

    //调用userDetailsService和密码处理
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(defaultPasswordEncoder);
    }
    //不进行认证的路径,可以直接访问
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/api/**");
    }
}

你可能感兴趣的:(java,java,开发语言,后端)