From 8da2bb00b3e73384a1f2a9a676b90e1295c8904d Mon Sep 17 00:00:00 2001 From: D <3066417822@qq.com> Date: Mon, 13 Nov 2023 21:12:03 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=89=E5=85=A8=E6=A1=86=E6=9E=B6=E5=92=8Cap?= =?UTF-8?q?i=E6=96=87=E6=A1=A3=E6=A1=86=E6=9E=B6=E5=8D=87=E7=BA=A7?= =?UTF-8?q?=E5=88=B0springboot3=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/launch.json | 15 ++ .vscode/settings.json | 3 + pom.xml | 39 +++-- ruoyi-admin/pom.xml | 28 ---- .../web/controller/tool/TestController.java | 43 +++--- .../ruoyi/web/core/config/SwaggerConfig.java | 135 +++--------------- ruoyi-common/pom.xml | 18 ++- .../framework/config/SecurityConfig.java | 111 +++++++------- 8 files changed, 136 insertions(+), 256 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..e28a3ad --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // 使用 IntelliSense 了解相关属性。 + // 悬停以查看现有属性的描述。 + // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "java", + "name": "RuoYiApplication", + "request": "launch", + "mainClass": "com.ruoyi.RuoYiApplication", + "projectName": "ruoyi-admin" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..c5f3f6b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.configuration.updateBuildConfiguration": "interactive" +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 7f90386..931343d 100644 --- a/pom.xml +++ b/pom.xml @@ -1,8 +1,7 @@ - 4.0.0 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 com.ruoyi ruoyi @@ -36,7 +35,7 @@ 4.1.2 2.3 0.9.1 - 3.0.3 + 4.3.0 @@ -44,11 +43,11 @@ - - - - - + + + + + javax.xml.bind @@ -57,13 +56,13 @@ - - - - - - - + + + + + + + @@ -201,13 +200,7 @@ com.github.xiaoymin - knife4j-micro-spring-boot-starter - ${knife4j.version} - - - - com.github.xiaoymin - knife4j-spring-boot-starter + knife4j-openapi3-jakarta-spring-boot-starter ${knife4j.version} diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index a972c7a..9d68248 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -23,19 +23,6 @@ true - - - io.springfox - springfox-boot-starter - - - - - io.swagger - swagger-models - 1.6.2 - - com.mysql @@ -59,18 +46,6 @@ com.ruoyi ruoyi-generator - - - - com.github.xiaoymin - knife4j-micro-spring-boot-starter - - - - com.github.xiaoymin - knife4j-spring-boot-starter - - @@ -79,9 +54,6 @@ org.springframework.boot spring-boot-maven-plugin 3.0.0 - - true - diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java index b4f6bac..d635fa9 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java @@ -4,6 +4,11 @@ import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -15,19 +20,13 @@ import org.springframework.web.bind.annotation.RestController; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.utils.StringUtils; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import io.swagger.annotations.ApiOperation; /** * swagger 用户测试方法 - * + * * @author ruoyi */ -@Api("用户信息管理") +@Tag(name = "用户信息管理") @RestController @RequestMapping("/test/user") public class TestController extends BaseController @@ -38,7 +37,7 @@ public class TestController extends BaseController users.put(2, new UserEntity(2, "ry", "admin123", "15666666666")); } - @ApiOperation("获取用户列表") + @Operation(summary = "获取用户列表") @GetMapping("/list") public R> userList() { @@ -46,8 +45,7 @@ public class TestController extends BaseController return R.ok(userList); } - @ApiOperation("获取用户详细") - @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class) + @Operation(summary = "获取用户详细") @GetMapping("/{userId}") public R getUser(@PathVariable Integer userId) { @@ -61,13 +59,7 @@ public class TestController extends BaseController } } - @ApiOperation("新增用户") - @ApiImplicitParams({ - @ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", dataTypeClass = Integer.class), - @ApiImplicitParam(name = "username", value = "用户名称", dataType = "String", dataTypeClass = String.class), - @ApiImplicitParam(name = "password", value = "用户密码", dataType = "String", dataTypeClass = String.class), - @ApiImplicitParam(name = "mobile", value = "用户手机", dataType = "String", dataTypeClass = String.class) - }) + @Operation(summary = "新增用户") @PostMapping("/save") public R save(UserEntity user) { @@ -79,7 +71,7 @@ public class TestController extends BaseController return R.ok(); } - @ApiOperation("更新用户") + @Operation(summary = "更新用户") @PutMapping("/update") public R update(@RequestBody UserEntity user) { @@ -96,8 +88,7 @@ public class TestController extends BaseController return R.ok(); } - @ApiOperation("删除用户信息") - @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class) + @Operation(summary = "删除用户信息") @DeleteMapping("/{userId}") public R delete(@PathVariable Integer userId) { @@ -113,19 +104,19 @@ public class TestController extends BaseController } } -@ApiModel(value = "UserEntity", description = "用户实体") +@Schema(description = "用户实体") class UserEntity { - @ApiModelProperty("用户ID") + @Schema(defaultValue = "用户ID") private Integer userId; - @ApiModelProperty("用户名称") + @Schema(defaultValue = "用户名称") private String username; - @ApiModelProperty("用户密码") + @Schema(defaultValue = "用户密码") private String password; - @ApiModelProperty("用户手机") + @Schema(defaultValue = "用户手机") private String mobile; public UserEntity() diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java b/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java index ae1c3ec..25c26a8 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java @@ -1,125 +1,36 @@ package com.ruoyi.web.core.config; -import java.util.ArrayList; -import java.util.List; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; +import io.swagger.v3.oas.models.ExternalDocumentation; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import org.springdoc.core.models.GroupedOpenApi; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import com.ruoyi.common.config.RuoYiConfig; -import io.swagger.annotations.ApiOperation; -import io.swagger.models.auth.In; -import springfox.documentation.builders.ApiInfoBuilder; -import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.service.ApiInfo; -import springfox.documentation.service.ApiKey; -import springfox.documentation.service.AuthorizationScope; -import springfox.documentation.service.Contact; -import springfox.documentation.service.SecurityReference; -import springfox.documentation.service.SecurityScheme; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spi.service.contexts.SecurityContext; -import springfox.documentation.spring.web.plugins.Docket; -/** - * Swagger2的接口配置 - * - * @author ruoyi - */ @Configuration -public class SwaggerConfig -{ - /** 系统基础配置 */ - @Autowired - private RuoYiConfig ruoyiConfig; +public class SwaggerConfig { - /** 是否开启swagger */ - @Value("${swagger.enabled}") - private boolean enabled; - - /** 设置请求的统一前缀 */ - @Value("${swagger.pathMapping}") - private String pathMapping; - - /** - * 创建API - */ @Bean - public Docket createRestApi() - { - return new Docket(DocumentationType.OAS_30) - // 是否启用Swagger - .enable(enabled) - // 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息) - .apiInfo(apiInfo()) - // 设置哪些接口暴露给Swagger展示 - .select() - // 扫描所有有注解的api,用这种方式更灵活 - .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) - // 扫描指定包中的swagger注解 - // .apis(RequestHandlerSelectors.basePackage("com.ruoyi.project.tool.swagger")) - // 扫描所有 .apis(RequestHandlerSelectors.any()) - .paths(PathSelectors.any()) - .build() - /* 设置安全模式,swagger可以设置访问token */ - .securitySchemes(securitySchemes()) - .securityContexts(securityContexts()) - .pathMapping(pathMapping); + public OpenAPI springShopOpenAPI() { + return new OpenAPI() + .info(new Info().title("RuoYi Geek") + .description("RuoYi Geek API文档") + .version("v1") + .license(new License().name("Apache 2.0").url("http://springdoc.org"))) + .externalDocs(new ExternalDocumentation() + .description("外部文档") + .url("https://springshop.wiki.github.org/docs")); } - /** - * 安全模式,这里指定token通过Authorization头请求头传递 - */ - private List securitySchemes() - { - List apiKeyList = new ArrayList(); - apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue())); - return apiKeyList; - } - - /** - * 安全上下文 - */ - private List securityContexts() - { - List securityContexts = new ArrayList<>(); - securityContexts.add( - SecurityContext.builder() - .securityReferences(defaultAuth()) - .operationSelector(o -> o.requestMappingPattern().matches("/.*")) - .build()); - return securityContexts; - } - - /** - * 默认的安全上引用 - */ - private List defaultAuth() - { - AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); - AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; - authorizationScopes[0] = authorizationScope; - List securityReferences = new ArrayList<>(); - securityReferences.add(new SecurityReference("Authorization", authorizationScopes)); - return securityReferences; - } - - /** - * 添加摘要信息 - */ - private ApiInfo apiInfo() - { - // 用ApiInfoBuilder进行定制 - return new ApiInfoBuilder() - // 设置标题 - .title("标题:若依管理系统_接口文档") - // 描述 - .description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...") - // 作者信息 - .contact(new Contact(ruoyiConfig.getName(), null, null)) - // 版本 - .version("版本号:" + ruoyiConfig.getVersion()) + @Bean + public GroupedOpenApi sysApi() { + return GroupedOpenApi.builder() + .group("sys系统") + .pathsToMatch("/system/**") + .packagesToScan( + "com.ruoyi.web.controller") .build(); } + } diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index b42d7ed..ebaed74 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -1,7 +1,6 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> ruoyi com.ruoyi @@ -67,11 +66,11 @@ - - com.baomidou - dynamic-datasource-spring-boot-starter - 3.5.2 - + + com.baomidou + dynamic-datasource-spring-boot-starter + 3.5.2 + @@ -143,6 +142,11 @@ mybatis-plus-boot-starter 3.5.3.1 + + + com.github.xiaoymin + knife4j-openapi3-jakarta-spring-boot-starter + diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java index e7b116f..125c961 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java @@ -1,18 +1,14 @@ package com.ruoyi.framework.config; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Configurable; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.ProviderManager; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; -//import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @@ -30,10 +26,9 @@ import com.ruoyi.framework.security.handle.LogoutSuccessHandlerImpl; * * @author ruoyi */ -@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) +@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true) @Configuration -public class SecurityConfig -{ +public class SecurityConfig { /** * 自定义用户认证逻辑 */ @@ -76,12 +71,6 @@ public class SecurityConfig * @return * @throws Exception */ -// @Bean -// @Override -// public AuthenticationManager authenticationManagerBean() throws Exception -// { -// return super.authenticationManagerBean(); -// } @Bean AuthenticationManager authenticationManager() { DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(); @@ -90,70 +79,72 @@ public class SecurityConfig return new ProviderManager(daoAuthenticationProvider); } - /** - * anyRequest | 匹配所有请求路径 - * access | SpringEl表达式结果为true时可以访问 - * anonymous | 匿名可以访问 - * denyAll | 用户不能访问 - * fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录) - * hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问 - * hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问 - * hasAuthority | 如果有参数,参数表示权限,则其权限可以访问 - * hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问 - * hasRole | 如果有参数,参数表示角色,则其角色可以访问 - * permitAll | 用户可以任意访问 - * rememberMe | 允许通过remember-me登录的用户访问 - * authenticated | 用户登录后可访问 + * anyRequest | 匹配所有请求路径 + * access | SpringEl表达式结果为true时可以访问 + * anonymous | 匿名可以访问 + * denyAll | 用户不能访问 + * fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录) + * hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问 + * hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问 + * hasAuthority | 如果有参数,参数表示权限,则其权限可以访问 + * hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问 + * hasRole | 如果有参数,参数表示角色,则其角色可以访问 + * permitAll | 用户可以任意访问 + * rememberMe | 允许通过remember-me登录的用户访问 + * authenticated | 用户登录后可访问 */ @Bean SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { - // 注解标记允许匿名访问的url - ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry registry = httpSecurity.authorizeRequests(); - permitAllUrl.getUrls().forEach(url -> registry.requestMatchers(url).permitAll()); - - httpSecurity + return httpSecurity // CSRF禁用,因为不使用session - .csrf().disable() + .csrf(csrf -> csrf.disable()) // 禁用HTTP响应标头 - .headers().cacheControl().disable().and() + .headers(headersCustomizer -> headersCustomizer.cacheControl().disable()) // 认证失败处理类 - .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() + .exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler)) // 基于token,所以不需要session - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() - .authorizeRequests(auth->auth // 对于登录login 注册register 验证码captchaImage 允许匿名访问 - .requestMatchers("/login", "/register", "/captchaImage").permitAll() - // 静态资源,可匿名访问 - .requestMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll() - .requestMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll() - // 除上面外的所有请求全部需要鉴权认证 - .anyRequest().authenticated()) - .headers().frameOptions().disable(); - // 添加Logout filter - httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler); - // 添加JWT filter - httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); - // 添加CORS filter - httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class); - httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class); - return httpSecurity.build(); + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .headers(headers -> headers.cacheControl().disable()) + // 注解标记允许匿名访问的url + .authorizeHttpRequests((requests) -> { + permitAllUrl.getUrls().forEach(url -> requests.requestMatchers(url).permitAll()); + // 对于登录login 注册register 验证码captchaImage 允许匿名访问 + requests.requestMatchers("/login", "/register", "/captchaImage").permitAll() + // 静态资源,可匿名访问 + .requestMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", + "/profile/**") + .permitAll() + .requestMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", + "/druid/**", "/*/api-docs/**") + .permitAll() + // 除上面外的所有请求全部需要鉴权认证 + .anyRequest().authenticated(); + }) + // 添加Logout filter + .logout(logout -> logout.logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler)) + // 添加JWT filter + .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class) + // 添加CORS filter + .addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class) + .addFilterBefore(corsFilter, LogoutFilter.class) + .build(); } /** * 强散列哈希加密实现 */ @Bean - public BCryptPasswordEncoder bCryptPasswordEncoder() - { + public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); } /** * 身份认证接口 */ -// @Override -// protected void configure(AuthenticationManagerBuilder auth) throws Exception -// { -// auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder()); -// } + // @Override + // protected void configure(AuthenticationManagerBuilder auth) throws Exception + // { + // auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder()); + // } }