diff --git a/db/0pigxx_boot.sql b/db/0pigxx_boot.sql index a78d6e69a..e2ec6068e 100644 --- a/db/0pigxx_boot.sql +++ b/db/0pigxx_boot.sql @@ -949,6 +949,7 @@ INSERT INTO `sys_role_menu` VALUES (1, 2102); INSERT INTO `sys_role_menu` VALUES (1, 2103); INSERT INTO `sys_role_menu` VALUES (1, 2104); INSERT INTO `sys_role_menu` VALUES (1, 2105); +INSERT INTO `sys_role_menu` VALUES (1, 2106); INSERT INTO `sys_role_menu` VALUES (1, 2200); INSERT INTO `sys_role_menu` VALUES (1, 2201); INSERT INTO `sys_role_menu` VALUES (1, 2202); @@ -1134,7 +1135,6 @@ INSERT INTO `sys_role_menu` VALUES (1, 9912); INSERT INTO `sys_role_menu` VALUES (1, 9913); INSERT INTO `sys_role_menu` VALUES (1, 9700); INSERT INTO `sys_role_menu` VALUES (1, 9710); -INSERT INTO `sys_role_menu` VALUES (1, 9711); INSERT INTO `sys_role_menu` VALUES (1, 9712); INSERT INTO `sys_role_menu` VALUES (1, 9713); INSERT INTO `sys_role_menu` VALUES (1, 9714); diff --git a/db/2pigxx.sql b/db/2pigxx.sql index c5e90bf94..3b43f2e88 100644 --- a/db/2pigxx.sql +++ b/db/2pigxx.sql @@ -738,6 +738,7 @@ INSERT INTO `sys_menu` (`menu_id`, `name`, `permission`, `path`, `component`, `p INSERT INTO `sys_menu` (`menu_id`, `name`, `permission`, `path`, `component`, `parent_id`, `icon`, `visible`, `sort_order`, `keep_alive`, `embedded`, `menu_type`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `tenant_id`) VALUES (9911, '路由管理', NULL, '/tools/route/index', NULL, 9910, 'iconfont icon-crew_feature', '1', 3, '0', '0', '0', 'admin', '2023-11-01 17:13:09', 'admin', '2023-11-27 14:53:33', '0', 1); INSERT INTO `sys_menu` (`menu_id`, `name`, `permission`, `path`, `component`, `parent_id`, `icon`, `visible`, `sort_order`, `keep_alive`, `embedded`, `menu_type`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `tenant_id`) VALUES (9912, '大屏看板', NULL, '/tools/data/report', NULL, 9910, 'iconfont icon-shuju', '1', 5, '0', '0', '0', 'admin', '2023-11-01 17:19:38', 'admin', '2023-11-27 14:53:38', '0', 1); INSERT INTO `sys_menu` (`menu_id`, `name`, `permission`, `path`, `component`, `parent_id`, `icon`, `visible`, `sort_order`, `keep_alive`, `embedded`, `menu_type`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `tenant_id`) VALUES (9913, '数据报表', NULL, '/tools/data/jimu', NULL, 9910, 'iconfont icon-ico_shuju', '1', 6, '0', '0', '0', 'admin', '2023-11-01 17:20:06', 'admin', '2023-11-27 14:53:43', '0', 1); + INSERT INTO `sys_menu` (`menu_id`, `name`, `permission`, `path`, `component`, `parent_id`, `icon`, `visible`, `sort_order`, `keep_alive`, `embedded`, `menu_type`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `tenant_id`) VALUES (9914, '路由维护', 'sys_route_manage', NULL, NULL, 9911, '1', '1', 3, '0', NULL, '1', '', NULL, 'admin', '2023-02-28 20:23:51', '0', 1); COMMIT; -- ---------------------------- @@ -930,6 +931,7 @@ INSERT INTO `sys_role_menu` VALUES (1, 2102); INSERT INTO `sys_role_menu` VALUES (1, 2103); INSERT INTO `sys_role_menu` VALUES (1, 2104); INSERT INTO `sys_role_menu` VALUES (1, 2105); +INSERT INTO `sys_role_menu` VALUES (1, 2106); INSERT INTO `sys_role_menu` VALUES (1, 2200); INSERT INTO `sys_role_menu` VALUES (1, 2201); INSERT INTO `sys_role_menu` VALUES (1, 2202); @@ -1113,6 +1115,7 @@ INSERT INTO `sys_role_menu` VALUES (1, 9910); INSERT INTO `sys_role_menu` VALUES (1, 9911); INSERT INTO `sys_role_menu` VALUES (1, 9912); INSERT INTO `sys_role_menu` VALUES (1, 9913); +INSERT INTO `sys_role_menu` VALUES (1, 9914); COMMIT; -- ---------------------------- diff --git a/pigx-app-server/pigx-app-server-biz/src/main/java/com/pig4cloud/pigx/app/controller/AppPageController.java b/pigx-app-server/pigx-app-server-biz/src/main/java/com/pig4cloud/pigx/app/controller/AppPageController.java index 3146fcdfb..ed9140299 100644 --- a/pigx-app-server/pigx-app-server-biz/src/main/java/com/pig4cloud/pigx/app/controller/AppPageController.java +++ b/pigx-app-server/pigx-app-server-biz/src/main/java/com/pig4cloud/pigx/app/controller/AppPageController.java @@ -1,5 +1,6 @@ package com.pig4cloud.pigx.app.controller; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.pig4cloud.pigx.app.api.entity.AppPageEntity; import com.pig4cloud.pigx.app.service.AppPageService; import com.pig4cloud.pigx.common.core.util.R; @@ -23,23 +24,31 @@ import org.springframework.web.bind.annotation.*; @SecurityRequirement(name = HttpHeaders.AUTHORIZATION) public class AppPageController { - private final AppPageService pageService; + private final AppPageService pageService; - /** - * 通过id查询文章资讯 - * @param id id - * @return R - */ - @Operation(summary = "通过id查询", description = "通过id查询") - @GetMapping("/{id}") - public R getById(@PathVariable("id") Long id) { - return R.ok(pageService.getById(id)); - } + /** + * 查询文章资讯 + * + * @param pageType pageType + * @return R + */ + @Operation(summary = "通过页面类型查询", description = "通过页面类型查询") + @GetMapping("/{pageType}") + public R getByPageType(@PathVariable("pageType") Long pageType) { + AppPageEntity appPage = pageService.getOne(Wrappers.lambdaQuery().eq(AppPageEntity::getPageType, pageType)); + return R.ok(appPage); + } - @Operation(summary = "更新页面", description = "更新页面") - @PutMapping - public R update(@RequestBody AppPageEntity page) { - return R.ok(pageService.updateById(page)); - } + /** + * 更新 + * + * @param page 页面 + * @return {@link R } + */ + @Operation(summary = "更新页面", description = "更新页面") + @PutMapping + public R update(@RequestBody AppPageEntity page) { + return R.ok(pageService.saveOrUpdate(page)); + } } diff --git a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/R.java b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/R.java index 6a63a640c..b03d81618 100644 --- a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/R.java +++ b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/R.java @@ -19,6 +19,7 @@ package com.pig4cloud.pigx.common.core.util; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyDescription; import com.pig4cloud.pigx.common.core.constant.CommonConstants; import io.swagger.v3.oas.annotations.media.Schema; @@ -96,6 +97,7 @@ public class R implements Serializable { return apiResult; } + @JsonProperty(access = JsonProperty.Access.READ_ONLY) public boolean isOk() { return this.code == CommonConstants.SUCCESS; } diff --git a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisCacheAutoConfiguration.java b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisCacheAutoConfiguration.java index 8bebbb3e7..b69489b51 100644 --- a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisCacheAutoConfiguration.java +++ b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisCacheAutoConfiguration.java @@ -17,6 +17,9 @@ package com.pig4cloud.pigx.common.data.cache; +import cn.hutool.core.util.ReflectUtil; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.pig4cloud.pigx.common.core.jackson.PigxJavaTimeModule; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizers; @@ -94,8 +97,12 @@ public class RedisCacheAutoConfiguration { } else { CacheProperties.Redis redisProperties = this.cacheProperties.getRedis(); RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); + + RedisSerializer jsonRedisSerializer = RedisSerializer.json(); + ObjectMapper objectMapper = (ObjectMapper) ReflectUtil.getFieldValue(jsonRedisSerializer, "mapper"); + objectMapper.registerModules(new PigxJavaTimeModule()); config = config.serializeValuesWith(RedisSerializationContext.SerializationPair - .fromSerializer(RedisSerializer.java())); + .fromSerializer(jsonRedisSerializer)); if (redisProperties.getTimeToLive() != null) { config = config.entryTtl(redisProperties.getTimeToLive()); } diff --git a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisTemplateConfiguration.java b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisTemplateConfiguration.java index cec14fade..954db3af2 100644 --- a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisTemplateConfiguration.java +++ b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisTemplateConfiguration.java @@ -17,6 +17,9 @@ package com.pig4cloud.pigx.common.data.cache; +import cn.hutool.core.util.ReflectUtil; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.pig4cloud.pigx.common.core.jackson.PigxJavaTimeModule; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; @@ -43,8 +46,14 @@ public class RedisTemplateConfiguration { RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setKeySerializer(RedisSerializer.string()); redisTemplate.setHashKeySerializer(RedisSerializer.string()); - redisTemplate.setValueSerializer(RedisSerializer.java()); - redisTemplate.setHashValueSerializer(RedisSerializer.java()); + + // 设置 redisTemplate 的序列化器为 json + RedisSerializer jsonRedisSerializer = RedisSerializer.json(); + ObjectMapper objectMapper = (ObjectMapper) ReflectUtil.getFieldValue(jsonRedisSerializer, "mapper"); + objectMapper.registerModules(new PigxJavaTimeModule()); + redisTemplate.setValueSerializer(jsonRedisSerializer); + redisTemplate.setHashValueSerializer(jsonRedisSerializer); + redisTemplate.setConnectionFactory(redisConnectionFactory); return redisTemplate; } diff --git a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/tenant/TenantContextHolderFilter.java b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/tenant/TenantContextHolderFilter.java index c902a41b8..b565e6458 100644 --- a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/tenant/TenantContextHolderFilter.java +++ b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/tenant/TenantContextHolderFilter.java @@ -17,6 +17,7 @@ package com.pig4cloud.pigx.common.data.tenant; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.StrUtil; import com.pig4cloud.pigx.admin.api.entity.SysTenant; @@ -40,7 +41,6 @@ import org.springframework.stereotype.Component; import org.springframework.web.filter.GenericFilterBean; import java.util.List; -import java.util.Objects; /** * @author lengleng @@ -100,12 +100,11 @@ public class TenantContextHolderFilter extends GenericFilterBean { return true; } - Cache.ValueWrapper valueWrapper = cache.get(SimpleKey.EMPTY); - if (Objects.isNull(valueWrapper)) { + List tenantList = cache.get(SimpleKey.EMPTY, List.class); + if (CollUtil.isEmpty(tenantList)) { return true; } - List tenantList = (List) valueWrapper.get(); boolean exist = tenantList.stream().anyMatch(tenant -> NumberUtil.equals(tenant.getId(), TenantContextHolder.getTenantId())); if (exist) { return true; diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxDefaultUserDetailsServiceImpl.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxDefaultUserDetailsServiceImpl.java index 88f43ac62..0383b3cf5 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxDefaultUserDetailsServiceImpl.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxDefaultUserDetailsServiceImpl.java @@ -22,6 +22,7 @@ import com.pig4cloud.pigx.admin.api.feign.RemoteUserService; import com.pig4cloud.pigx.common.core.constant.CacheConstants; import com.pig4cloud.pigx.common.core.constant.enums.UserTypeEnum; import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.common.core.util.RetOps; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -31,6 +32,9 @@ import org.springframework.context.annotation.Primary; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; +import java.util.Objects; +import java.util.Optional; + /** * 用户详细信息 default * @@ -41,47 +45,49 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException; @RequiredArgsConstructor public class PigxDefaultUserDetailsServiceImpl implements PigxUserDetailsService { - private final RemoteUserService remoteUserService; + private final RemoteUserService remoteUserService; - private final CacheManager cacheManager; + private final CacheManager cacheManager; - /** - * 用户密码登录 - * @param username 用户名 - * @return - * @throws UsernameNotFoundException - */ - @Override - @SneakyThrows - public UserDetails loadUserByUsername(String username) { - Cache cache = cacheManager.getCache(CacheConstants.USER_DETAILS); - if (cache != null && cache.get(username) != null) { - return cache.get(username, PigxUser.class); - } + /** + * 用户密码登录 + * + * @param username 用户名 + * @return + * @throws UsernameNotFoundException + */ + @Override + @SneakyThrows + public UserDetails loadUserByUsername(String username) { + Cache cache = cacheManager.getCache(CacheConstants.USER_DETAILS); + if (Objects.nonNull(cache) && Objects.nonNull(cache.get(username))) { + return getUserDetails(Optional.ofNullable(cache.get(username, UserInfo.class))); + } - R result = remoteUserService.info(username); - UserDetails userDetails = getUserDetails(result); - cache.put(username, userDetails); - return userDetails; - } + R result = remoteUserService.info(username); + Optional userInfoOptional = RetOps.of(result).getData(); + userInfoOptional.ifPresent(userInfo -> Objects.requireNonNull(cache).put(username, userInfo)); + return getUserDetails(userInfoOptional); + } - /** - * 通过用户实体查询 - * @param pigxUser user - * @return - */ - @Override - public UserDetails loadUserByUser(PigxUser pigxUser) { - // 避免 C端用户通过接口调用B端接口的安全问题 - if (UserTypeEnum.TOB.getStatus().equals(pigxUser.getUserType())) { - return loadUserByUsername(pigxUser.getUsername()); - } - return null; - } + /** + * 通过用户实体查询 + * + * @param pigxUser user + * @return + */ + @Override + public UserDetails loadUserByUser(PigxUser pigxUser) { + // 避免 C端用户通过接口调用B端接口的安全问题 + if (UserTypeEnum.TOB.getStatus().equals(pigxUser.getUserType())) { + return loadUserByUsername(pigxUser.getUsername()); + } + return null; + } - @Override - public int getOrder() { - return Integer.MIN_VALUE; - } + @Override + public int getOrder() { + return Integer.MIN_VALUE; + } } diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxMobileUserDetailServiceImpl.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxMobileUserDetailServiceImpl.java index b02c4f004..493e28a91 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxMobileUserDetailServiceImpl.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxMobileUserDetailServiceImpl.java @@ -4,6 +4,7 @@ import com.pig4cloud.pigx.admin.api.dto.UserInfo; import com.pig4cloud.pigx.admin.api.feign.RemoteUserService; import com.pig4cloud.pigx.common.core.constant.SecurityConstants; import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.common.core.util.RetOps; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -25,7 +26,7 @@ public class PigxMobileUserDetailServiceImpl implements PigxUserDetailsService { @SneakyThrows public UserDetails loadUserByUsername(String phone) { R result = remoteUserService.social(phone); - return getUserDetails(result); + return getUserDetails(RetOps.of(result).getData()); } @Override diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxRemoteRegisteredClientRepository.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxRemoteRegisteredClientRepository.java index 77bb779e2..1d56eab6b 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxRemoteRegisteredClientRepository.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxRemoteRegisteredClientRepository.java @@ -10,7 +10,8 @@ import com.pig4cloud.pigx.common.core.constant.SecurityConstants; import com.pig4cloud.pigx.common.core.util.RetOps; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; -import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; import org.springframework.security.oauth2.core.OAuth2Error; @@ -24,6 +25,7 @@ import org.springframework.security.oauth2.server.authorization.settings.TokenSe import java.time.Duration; import java.util.Arrays; import java.util.Map; +import java.util.Objects; import java.util.Optional; /** @@ -35,107 +37,123 @@ import java.util.Optional; @RequiredArgsConstructor public class PigxRemoteRegisteredClientRepository implements RegisteredClientRepository { - /** - * 刷新令牌有效期默认 30 天 - */ - private final static int refreshTokenValiditySeconds = 60 * 60 * 24 * 30; + /** + * 刷新令牌有效期默认 30 天 + */ + private final static int refreshTokenValiditySeconds = 60 * 60 * 24 * 30; - /** - * 请求令牌有效期默认 12 小时 - */ - private final static int accessTokenValiditySeconds = 60 * 60 * 12; + /** + * 请求令牌有效期默认 12 小时 + */ + private final static int accessTokenValiditySeconds = 60 * 60 * 12; - private final RemoteClientDetailsService clientDetailsService; + private final RemoteClientDetailsService clientDetailsService; - /** - * Saves the registered client. - * - *

- * IMPORTANT: Sensitive information should be encoded externally from the - * implementation, e.g. {@link RegisteredClient#getClientSecret()} - * @param registeredClient the {@link RegisteredClient} - */ - @Override - public void save(RegisteredClient registeredClient) { - } + private final CacheManager cacheManager; - /** - * Returns the registered client identified by the provided {@code id}, or - * {@code null} if not found. - * @param id the registration identifier - * @return the {@link RegisteredClient} if found, otherwise {@code null} - */ - @Override - public RegisteredClient findById(String id) { - throw new UnsupportedOperationException(); - } + /** + * Saves the registered client. + * + *

+ * IMPORTANT: Sensitive information should be encoded externally from the + * implementation, e.g. {@link RegisteredClient#getClientSecret()} + * + * @param registeredClient the {@link RegisteredClient} + */ + @Override + public void save(RegisteredClient registeredClient) { + } - /** - * Returns the registered client identified by the provided {@code clientId}, or - * {@code null} if not found. - * @param clientId the client identifier - * @return the {@link RegisteredClient} if found, otherwise {@code null} - */ + /** + * Returns the registered client identified by the provided {@code id}, or + * {@code null} if not found. + * + * @param id the registration identifier + * @return the {@link RegisteredClient} if found, otherwise {@code null} + */ + @Override + public RegisteredClient findById(String id) { + throw new UnsupportedOperationException(); + } - /** - * 重写原生方法支持redis缓存 - * @param clientId - * @return - */ - @Override - @SneakyThrows - @Cacheable(value = CacheConstants.CLIENT_DETAILS_KEY, key = "#clientId", unless = "#result == null") - public RegisteredClient findByClientId(String clientId) { + /** + * Returns the registered client identified by the provided {@code clientId}, or + * {@code null} if not found. + * @param clientId the client identifier + * @return the {@link RegisteredClient} if found, otherwise {@code null} + */ - SysOauthClientDetails clientDetails = RetOps - .of(clientDetailsService.getClientDetailsById(clientId)) - .getData() - .orElseThrow(() -> new OAuth2AuthorizationCodeRequestAuthenticationException( - new OAuth2Error("客户端查询异常,请检查数据库链接"), null)); + /** + * 按客户端 ID 查找 + * + * @param clientId 客户端 ID + * @return {@link RegisteredClient } + */ + @Override + @SneakyThrows + public RegisteredClient findByClientId(String clientId) { - RegisteredClient.Builder builder = RegisteredClient.withId(clientDetails.getClientId()) - .clientId(clientDetails.getClientId()) - .clientSecret(SecurityConstants.NOOP + clientDetails.getClientSecret()) - .clientAuthenticationMethods(clientAuthenticationMethods -> { - clientAuthenticationMethods.add(ClientAuthenticationMethod.CLIENT_SECRET_BASIC); - clientAuthenticationMethods.add(ClientAuthenticationMethod.CLIENT_SECRET_POST); - }); - // 授权模式 - Arrays.stream(clientDetails.getAuthorizedGrantTypes()) - .forEach(grant -> builder.authorizationGrantType(new AuthorizationGrantType(grant))); + Cache cache = cacheManager.getCache(CacheConstants.CLIENT_DETAILS_KEY); + SysOauthClientDetails clientDetails = null; + if (Objects.nonNull(cache) && Objects.nonNull(cache.get(clientId))) { + clientDetails = cache.get(clientId, SysOauthClientDetails.class); + } - // 回调地址 - Optional.ofNullable(clientDetails.getWebServerRedirectUri()) - .ifPresent(redirectUri -> Arrays.stream(redirectUri.split(StrUtil.COMMA)) - .filter(StrUtil::isNotBlank) - .forEach(builder::redirectUri)); + if (Objects.isNull(clientDetails)) { + SysOauthClientDetails fetchedClientDetails = RetOps + .of(clientDetailsService.getClientDetailsById(clientId)) + .getData() + .orElseThrow(() -> new OAuth2AuthorizationCodeRequestAuthenticationException( + new OAuth2Error("客户端查询异常,请检查数据库链接"), null)); - // scope - Optional.ofNullable(clientDetails.getScope()) - .ifPresent(scope -> Arrays.stream(scope.split(StrUtil.COMMA)) - .filter(StrUtil::isNotBlank) - .forEach(builder::scope)); + clientDetails = fetchedClientDetails; + Optional.ofNullable(cache).ifPresent(c -> c.put(clientId, fetchedClientDetails)); + } - // 注入扩展配置 - Optional.ofNullable(clientDetails.getAdditionalInformation()).ifPresent(ext -> { - Map map = JSONUtil.parseObj(ext).toBean(Map.class); - builder.clientSettings(ClientSettings.withSettings(map) - .requireProofKey(false) - .requireAuthorizationConsent(!BooleanUtil.toBoolean(clientDetails.getAutoapprove())) - .build()); - }); + final SysOauthClientDetails finalClientDetails = clientDetails; - return builder - .tokenSettings(TokenSettings.builder() - .accessTokenFormat(OAuth2TokenFormat.REFERENCE) - .accessTokenTimeToLive(Duration.ofSeconds( - Optional.ofNullable(clientDetails.getAccessTokenValidity()).orElse(accessTokenValiditySeconds))) - .refreshTokenTimeToLive(Duration.ofSeconds(Optional.ofNullable(clientDetails.getRefreshTokenValidity()) - .orElse(refreshTokenValiditySeconds))) - .build()) + RegisteredClient.Builder builder = RegisteredClient.withId(finalClientDetails.getClientId()) + .clientId(finalClientDetails.getClientId()) + .clientSecret(SecurityConstants.NOOP + finalClientDetails.getClientSecret()) + .clientAuthenticationMethods(clientAuthenticationMethods -> { + clientAuthenticationMethods.add(ClientAuthenticationMethod.CLIENT_SECRET_BASIC); + clientAuthenticationMethods.add(ClientAuthenticationMethod.CLIENT_SECRET_POST); + }); - .build(); + // 授权模式 + Arrays.stream(finalClientDetails.getAuthorizedGrantTypes()) + .forEach(grant -> builder.authorizationGrantType(new AuthorizationGrantType(grant))); - } + // 回调地址 + Optional.ofNullable(finalClientDetails.getWebServerRedirectUri()) + .ifPresent(redirectUri -> Arrays.stream(redirectUri.split(StrUtil.COMMA)) + .filter(StrUtil::isNotBlank) + .forEach(builder::redirectUri)); + + // scope + Optional.ofNullable(finalClientDetails.getScope()) + .ifPresent(scope -> Arrays.stream(scope.split(StrUtil.COMMA)) + .filter(StrUtil::isNotBlank) + .forEach(builder::scope)); + + // 注入扩展配置 + Optional.ofNullable(finalClientDetails.getAdditionalInformation()).ifPresent(ext -> { + Map map = JSONUtil.parseObj(ext).toBean(Map.class); + builder.clientSettings(ClientSettings.withSettings(map) + .requireProofKey(false) + .requireAuthorizationConsent(!BooleanUtil.toBoolean(finalClientDetails.getAutoapprove())) + .build()); + }); + + return builder + .tokenSettings(TokenSettings.builder() + .accessTokenFormat(OAuth2TokenFormat.REFERENCE) + .accessTokenTimeToLive(Duration.ofSeconds( + Optional.ofNullable(finalClientDetails.getAccessTokenValidity()).orElse(accessTokenValiditySeconds))) + .refreshTokenTimeToLive(Duration.ofSeconds(Optional.ofNullable(finalClientDetails.getRefreshTokenValidity()) + .orElse(refreshTokenValiditySeconds))) + .build()) + .build(); + } } diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxUserDetailsService.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxUserDetailsService.java index 1cbed6c5c..b3eec7f70 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxUserDetailsService.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxUserDetailsService.java @@ -22,8 +22,6 @@ import com.pig4cloud.pigx.admin.api.entity.SysUser; import com.pig4cloud.pigx.common.core.constant.CommonConstants; import com.pig4cloud.pigx.common.core.constant.SecurityConstants; import com.pig4cloud.pigx.common.core.constant.enums.UserTypeEnum; -import com.pig4cloud.pigx.common.core.util.R; -import com.pig4cloud.pigx.common.core.util.RetOps; import org.springframework.core.Ordered; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; @@ -31,10 +29,7 @@ import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; +import java.util.*; /** * @author lengleng @@ -63,16 +58,14 @@ public interface PigxUserDetailsService extends UserDetailsService, Ordered { } /** - * 构建userdetails + * 获取用户详细信息 * - * @param result 用户信息 - * @return UserDetails - * @throws UsernameNotFoundException + * @param userInfoOptional 用户信息:可选 + * @return {@link UserDetails } */ - default UserDetails getUserDetails(R result) { + default UserDetails getUserDetails(Optional userInfoOptional) { // @formatter:off - return RetOps.of(result) - .getData() + return userInfoOptional .map(this::convertUserDetails) .orElseThrow(() -> new UsernameNotFoundException("用户不存在")); // @formatter:on diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysFileServiceImpl.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysFileServiceImpl.java index d0eadd9a0..cbe5d200e 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysFileServiceImpl.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysFileServiceImpl.java @@ -24,6 +24,7 @@ import cn.hutool.core.lang.tree.TreeNode; import cn.hutool.core.lang.tree.TreeUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.URLUtil; import cn.hutool.crypto.SecureUtil; import com.amazonaws.services.s3.model.S3Object; import com.baomidou.mybatisplus.core.toolkit.Wrappers; @@ -43,6 +44,7 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.AllArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -112,6 +114,7 @@ public class SysFileServiceImpl extends ServiceImpl impl response.setContentType("application/octet-stream; charset=UTF-8"); // 文件唯一hash response.addHeader("Hash", sysFile.getHash()); + response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + URLUtil.encode(sysFile.getOriginal())); IoUtil.copy(s3Object.getObjectContent(), response.getOutputStream()); } catch (Exception e) { log.error("文件读取异常: {}", e.getLocalizedMessage()); diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysMenuServiceImpl.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysMenuServiceImpl.java index ac1ac0da3..ad72ce650 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysMenuServiceImpl.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysMenuServiceImpl.java @@ -110,6 +110,7 @@ public class SysMenuServiceImpl extends ServiceImpl impl List> collect = baseMapper .selectList(Wrappers.lambdaQuery() + .eq(Objects.nonNull(parentId),SysMenu::getParentId, parentId) .like(StrUtil.isNotBlank(menuName), SysMenu::getName, menuName) .eq(StrUtil.isNotBlank(type), SysMenu::getMenuType, type) .orderByAsc(SysMenu::getSortOrder)) diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/config/PigxCodeGenDefaultProperties.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/config/PigxCodeGenDefaultProperties.java index 806207672..6d9dfe928 100644 --- a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/config/PigxCodeGenDefaultProperties.java +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/config/PigxCodeGenDefaultProperties.java @@ -78,7 +78,7 @@ public class PigxCodeGenDefaultProperties implements InitializingBean { /** * 是否同步路由 */ - private String syncRoute = "1"; + private String syncRoute = "0"; /** * 集成mybatis动态数据源