欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

spring-boot整合spring-security,Swagger使用spring-security认证

程序员文章站 2024-03-18 13:57:28
...

spring-boot整合spring-security

  • spring-boot

  • spring-security

  • swagger2

  • Mybatis-plus

  • Mysql

    本文基于IDEA工具

创建spring-boot项目

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

spring-boot整合spring-security,Swagger使用spring-security认证

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页面,对刚写的接口进行数据测试;

spring-boot整合spring-security,Swagger使用spring-security认证

到此,就大功告成!

相关标签: 后台