当先锋百科网

首页 1 2 3 4 5 6 7

spring-boot整合spring-security

  • spring-boot

  • spring-security

  • swagger2

  • Mybatis-plus

  • Mysql

    本文基于IDEA工具

创建spring-boot项目

使用IDEA Spring Initializr创建一个spring-boot项目,在创建的时候可以根据需要选择依赖

在这里插入图片描述

pom.xml依赖

中间踩过几次坑:

一个是lombok没配置版本号的时候,默认是 1.18.12 , 在使用的时候会报错

另一个是swagger的版本,开始是使用的3.0.0-SNAPSHOT,这个版本里面没有@EnableSwagger2这个注解,

改成了@EnableSwagger2WebMvc@EnableSwagger2WebFlux这两个注解,后面还是改用2.9.2

<dependencies>
    <!-- security 依赖-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- mysql 数据库驱动jar包 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <scope>runtime</scope>
    </dependency>

    <!-- 数据库连接池 -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.20</version>
    </dependency>

    <!-- mybatis-plus 依赖 -->
    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-boot-starter</artifactId>
      <version>3.1.1</version>
    </dependency>

    <!-- mybatis-plus 代码生成依赖 -->
    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-generator</artifactId>
      <version>3.1.1</version>
    </dependency>

    <!-- velocity 模板依赖,代码生成需要 -->
    <dependency>
      <groupId>org.apache.velocity</groupId>
      <artifactId>velocity-engine-core</artifactId>
      <version>2.1</version>
    </dependency>

    <!-- lombok工具 -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.10</version>
      <optional>true</optional>
    </dependency>

    <!-- 日志 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-logging</artifactId>
    </dependency>

    <!-- swagger2 依赖 -->
    <dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-swagger2</artifactId>
      <version>2.9.2</version>
    </dependency>

    <dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-swagger-ui</artifactId>
      <version>2.9.2</version>
    </dependency>

    <!-- 测试依赖 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
      <exclusions>
        <exclusion>
          <groupId>org.junit.vintage</groupId>
          <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>
配置文件

个人喜欢使用yml格式,所以将默认的properties文件改成yml后缀

server:
  port: 8080

spring:
  profiles:
    active: dev
  datasource:
    url: jdbc:mysql://loaclhost:3306/spring-security-oauth2?useUnicode=true&serverTimezone=GMT&useSSL=false&characterEncoding=utf8
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      initial-size: 10
      min-idle: 10
      max-active: 50
      max-wait: 30000

mybatis-plus:
  mapper-locations: classpath:/mapper/*/*Mapper.xml
  type-aliases-package: com.peas.module.*.entity
  configuration:
    map-underscore-to-camel-case: true # 开户驼峰命名
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 在控制台打印sql
  global-config:
    db-config:
      logic-not-delete-value: 0 # 逻辑删除 未删除的值
      logic-delete-value: 1 # 逻辑删除 已删除的值

logging:
  level:
    com.peas: debug

配置swagger

新建 SwaggerConfig.java文件,代码如下:

这里不用提供认证功能,直接使用spring-security登录认证后进入swagger-ui页面,调用接口就不需再认证

@Configuration
@EnableSwagger2
public class SwaggerConfig {

  @Bean
  public Docket docket() {
    return new Docket(DocumentationType.SWAGGER_2)
      .apiInfo(apiInfo())
      .select()
      .apis(RequestHandlerSelectors.basePackage("com.peas.module"))
      .build();
  }

  private ApiInfo apiInfo() {
    return new ApiInfoBuilder()
      .title("Swagger 文档")
      .description("副标题")
      .version("1.0.0")
      .build();
  }

}
配置 swagger访问资源地址映射

新建WebMvcConfig.java,继承WebMvcConfigurationSupport类,重写addResourceHandlers(ResourceHandlerRegistry registry)方法,将swagger对应资源作映射,如果不做这一步,后面在访问swagger-ui.html页面的时候会找不到对应资源,报404错误,代码如下:

@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

  @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("swagger-ui.html")
      .addResourceLocations("classpath:/META-INF/resources/");
    registry.addResourceHandler("/webjars/**")
      .addResourceLocations("classpath:/META-INF/resources/webjars/");
  }
}
编写UserDetailService实现类

在配置spring-security之前,需先编写一个UserDetailService接口的实现类,在配置spring-security的时候需要使用到,这个类是根据用户传入的用户名去查询对应的用户密码与角色列表,并返回一个UserDetails类,我的代码如下,具体根据实际情况:

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

  @Autowired
  IUserService userService;
  @Autowired
  IUserRoleService userRoleService;
  @Autowired
  IRoleService roleService;


  @Override
  public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
    List<GrantedAuthority> grantedAuthorityList = new ArrayList<>();
    User user = userService.getUserByUserName(userName);
    List<Role> roleList = roleService.getRoleListByRoleIds(userRoleService.getRoleIdsByUserId(user.getUserId()));
    for (Role role : roleList) {
      if (!StringUtils.isEmpty(role.getRoleCode())) {
          // 获取角色列表中的角色
        grantedAuthorityList.add(new SimpleGrantedAuthority(role.getRoleCode()));
      }
    }
    return new org.springframework.security.core.userdetails.User(user.getName(), user.getPassword(), grantedAuthorityList);
  }
}
spring-security 配置

新建SpringSecurityConfig.java,代码如下:

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  UserDetailsServiceImpl userDetailsService;

  private PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
  }

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService) // 这里是前面实现的UserDetailServiceImpl类
      .passwordEncoder(passwordEncoder()); // 密码加密方式
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .csrf().disable()
      .authorizeRequests()
      // .antMatchers("/webjars/**", "/resources/**", "/swagger-ui.html", "/swagger-resources/**", "/v2/api-docs").permitAll() // 如果swagger提供认证功能,这里需要对swagger的资源地址放行,因为我这里swagger没有提供认证功能,所以全部都需要进行使用spring-security认证后才能访问
      .antMatchers("/oauth/**", "/login/**", "/logout/**").permitAll() // 定义的地址不需要认证便可以访问
      .anyRequest().authenticated() // 其它未定义的,全部需要认证后才能访问
      .and()
      .formLogin() // 使用表单登录
      .and()
      .logout()
      .logoutSuccessUrl("/login"); // 退出登录后,跳转到登录
  }
}
代码生成工具类

以下是我的代码,自己按需修改:

public class MysqlGenerator {

  /**
   * <p>
   * 读取控制台内容
   * </p>
   */
  public static String scanner(String tip) {
    Scanner scanner = new Scanner(System.in);
    StringBuilder help = new StringBuilder();
    help.append("请输入" + tip + ":");
    System.out.println(help.toString());
    if (scanner.hasNext()) {
      String ipt = scanner.next();
      if (StringUtils.isNotEmpty(ipt)) {
        return ipt;
      }
    }
    throw new MybatisPlusException("请输入正确的" + tip + "!");
  }

  /**
   * RUN THIS
   */
  public static void main(String[] args) {
    // 代码生成器
    AutoGenerator mpg = new AutoGenerator();

    // 全局配置
    GlobalConfig gc = new GlobalConfig();
    //生成文件的输出目录(下面两行无需改动)
    String projectPath = System.getProperty("user.dir");
    gc.setOutputDir(projectPath + "/src/main/java");
    // 作者
    gc.setAuthor("oldPeas");
    //是否覆盖文件
    gc.setFileOverride(true);
    //生成后打开文件
    gc.setOpen(false);
    mpg.setGlobalConfig(gc);

    // 数据源配置
    DataSourceConfig dsc = new DataSourceConfig();
    dsc.setDbType(DbType.MYSQL);
    dsc.setUrl("jdbc:mysql://localhost:3306/dbName?useUnicode=true&serverTimezone=GMT&useSSL=false&characterEncoding=utf8");
    // dsc.setSchemaName("public");
    dsc.setDriverName("com.mysql.cj.jdbc.Driver");
    dsc.setUsername("root");
    dsc.setPassword("root");
    mpg.setDataSource(dsc);

    // 包配置
    PackageConfig pc = new PackageConfig();
    pc.setModuleName(scanner("模块名")); // 控制台输入模块名
    pc.setParent("com.peas.module"); // 所有生成代码的根目录
    pc.setEntity("entity"); // 生成的实体类存放的文件夹
    pc.setController("controller.impl"); // 控制器存放位置,因为我自己对控制器定义了一层接口,所以多加了一层路径
    pc.setService("service"); 
    pc.setServiceImpl("service.impl");
    pc.setMapper("mapper");
    pc.setXml("mapper.xml");
    mpg.setPackageInfo(pc);

    // 自定义配置
    InjectionConfig cfg = new InjectionConfig() {
      @Override
      public void initMap() {
        // to do nothing
      }
    };
    List<FileOutConfig> focList = new ArrayList<>();
    // 如果模板引擎是 freemarker
    //String templatePath = "/templates/mapper.xml.ftl";
    // 如果您选择了非默认引擎,需要在 AutoGenerator 中 设置模板引擎
    //mpg.setTemplateEngine(new FreemarkerTemplateEngine());
    // 如果模板引擎是 velocity
     String templatePath = "/templates/mapper.xml.vm";

    focList.add(new FileOutConfig(templatePath) {
      @Override
      public String outputFile(TableInfo tableInfo) {
        // 自定义输入文件名称
        return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
          + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
      }
    });
    cfg.setFileOutConfigList(focList);
    mpg.setCfg(cfg);
    mpg.setTemplate(new TemplateConfig().setXml(null));

    // 策略配置
    StrategyConfig strategy = new StrategyConfig();
    strategy.setNaming(NamingStrategy.underline_to_camel);
    strategy.setColumnNaming(NamingStrategy.underline_to_camel);
//        strategy.setSuperEntityClass("com.baomidou.mybatisplus.extension.activerecord.Model");
    strategy.setEntityLombokModel(true);
//        strategy.setSuperControllerClass("com.baomidou.mybatisplus.samples.generator.common.BaseController");
    strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
//        strategy.setSuperEntityColumns("id");
    strategy.setControllerMappingHyphenStyle(true);
    strategy.setTablePrefix(pc.getModuleName() + "_");
    mpg.setStrategy(strategy);
    // 选择 freemarker 引擎需要指定如下加,注意 pom 依赖必须有!
//        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
    mpg.execute();
  }

}
编写测试接口

因为我在控制器上面加了一层接口,所以需要先写一个对应的接口,这样可以把Swagger的注解配置和MVC的映射都写在接口里面,实现类里面代码看起来就不会那么乱

控制器接口代码:

@RequestMapping("/sys/user")
@Api(tags = "用户信息")
public interface UserController {

  @GetMapping
  @ApiOperation("根据ID查询用户信息")
  User getUserById(Integer id);

}

控制器实现类代码:

@RestController
public class UserControllerImpl implements UserController {

  @Autowired
  IUserService userService;

  @Override
  public User getUserById(Integer id) {
    return userService.getById(id);
  }
}
测试

现在所有的准备工作已经完成,就开始测试,启动项目,在浏览器里面输入地址:http://localhost:8080/swagger-ui.html,因为当前未登录,会跳转到登录页面,然后输入正确的账号密码,就可以进入到Swagger页面,对刚写的接口进行数据测试;

在这里插入图片描述

到此,就大功告成!