From d4bb9e3772839092bf2f513bac487f95c51b593f Mon Sep 17 00:00:00 2001 From: xinhao <1344650328@qq.com> Date: Mon, 3 Jul 2023 14:54:52 +0800 Subject: [PATCH 01/10] #1251 Resolved two registration issues (#1383) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 章新好 Sunny Zhang --- .../src/main/java/cn/hippo4j/discovery/core/Lease.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/threadpool/server/discovery/src/main/java/cn/hippo4j/discovery/core/Lease.java b/threadpool/server/discovery/src/main/java/cn/hippo4j/discovery/core/Lease.java index 0d796f9e..f1b37ceb 100644 --- a/threadpool/server/discovery/src/main/java/cn/hippo4j/discovery/core/Lease.java +++ b/threadpool/server/discovery/src/main/java/cn/hippo4j/discovery/core/Lease.java @@ -47,8 +47,8 @@ public class Lease { public Lease(T r) { holder = r; registrationTimestamp = System.currentTimeMillis(); - lastUpdateTimestamp = registrationTimestamp; duration = DEFAULT_DURATION_IN_SECS; + lastUpdateTimestamp = registrationTimestamp + duration; } public void renew() { From 10bc5c300fce1d86e4cb3865da37a0e630843d5c Mon Sep 17 00:00:00 2001 From: LauItachi <22516902+MagikLau@users.noreply.github.com> Date: Thu, 6 Jul 2023 16:13:58 +0800 Subject: [PATCH 02/10] Update AdaptedThreadPoolDestroyPostProcessor.java add default impl (#1384) Fix match case: spring-beans-4.3.21.RELEASE.jar Forked from: spring-beans-5.1.14.RELEASE.jar --- .../AdaptedThreadPoolDestroyPostProcessor.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/starters/threadpool/server/src/main/java/cn/hippo4j/springboot/starter/support/AdaptedThreadPoolDestroyPostProcessor.java b/starters/threadpool/server/src/main/java/cn/hippo4j/springboot/starter/support/AdaptedThreadPoolDestroyPostProcessor.java index 0490b32b..ce425560 100644 --- a/starters/threadpool/server/src/main/java/cn/hippo4j/springboot/starter/support/AdaptedThreadPoolDestroyPostProcessor.java +++ b/starters/threadpool/server/src/main/java/cn/hippo4j/springboot/starter/support/AdaptedThreadPoolDestroyPostProcessor.java @@ -78,6 +78,20 @@ public class AdaptedThreadPoolDestroyPostProcessor implements DestructionAwareBe .ifPresent(executorHolder -> destroyAdaptedThreadPoolExecutor(beanName, executorHolder)); } + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + // forked default implementation from spring-beans-5.1.14.RELEASE.jar + // org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization + return bean; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + // forked default implementation from spring-beans-5.1.14.RELEASE.jar + // org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization + return bean; + } + private void destroyAdaptedThreadPoolExecutor(String beanName, ThreadPoolExecutorHolder executorHolder) { try { if (log.isDebugEnabled()) { From 41514383bf6b70ccfd9bd8ae5a0eaf58de36ef34 Mon Sep 17 00:00:00 2001 From: magestack Date: Mon, 24 Jul 2023 23:24:05 +0800 Subject: [PATCH 03/10] Update README.md (#1398) --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e93b2368..afaeb232 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,8 @@ For full documentation & more details, visit: [Docs](https://www.hippo4j.cn) - [[ JavaGuide ]](https://github.com/Snailclimb/JavaGuide):一份涵盖大部分 Java 程序员所需要掌握的核心知识。 - [[ toBeBetterJavaer ]](https://github.com/itwanger/toBeBetterJavaer):一份通俗易懂、风趣幽默的 Java 学习指南。 - [[ Jpom ]](https://gitee.com/dromara/Jpom):简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件。 -- [[ CongoMall ]](https://gitee.com/opengoofy/congomall):作者的另一个开源项目刚果商城,包含了商城业务和基础架构两大模块。 +- [[ 12306 ]](https://gitee.com/nageoffer/12306):完成高仿 12306 用户+抢票+订单+支付服务,帮助学生主打就业的项目。 +- [[ CongoMall ]](https://gitee.com/nageoffer/congomall):企业级商城,基于 DDD 领域驱动模型开发,包含商城业务和基础架构。 ### 贡献者 From 8c8205b55283658e61593c3d437661fc7d34f036 Mon Sep 17 00:00:00 2001 From: magestack Date: Mon, 24 Jul 2023 23:33:00 +0800 Subject: [PATCH 04/10] Update doc (#1399) * Update docs * Update users.md --- docs/docusaurus.config.js | 388 +++++++++--------- .../docusaurus-plugin-content-pages/users.md | 5 +- docs/src/pages/users.md | 5 +- 3 files changed, 200 insertions(+), 198 deletions(-) diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 2c6faa93..26890a2a 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -6,215 +6,211 @@ const darkCodeTheme = require('prism-react-renderer/themes/dracula'); /** @type {import('@docusaurus/types').Config} */ const config = { - title: 'Hippo4j', - tagline: '动态可观测线程池框架,为业务系统提高线上运行保障能力', - url: 'https://hippo4j.cn', - baseUrl: '/', - onBrokenLinks: 'throw', - onBrokenMarkdownLinks: 'warn', - favicon: 'img/hippo4j_favicon.ico', - // GitHub pages deployment config. - // If you aren't using GitHub pages, you don't need these. - organizationName: 'hippo4j', // Usually your GitHub org/user name. - projectName: 'hippo4j.github.io', // Usually your repo name. - deploymentBranch: 'main', + title: 'Hippo4j', + tagline: '动态可观测线程池框架,为业务系统提高线上运行保障能力', + url: 'https://hippo4j.cn', + baseUrl: '/', + onBrokenLinks: 'throw', + onBrokenMarkdownLinks: 'warn', + favicon: 'img/hippo4j_favicon.ico', + // GitHub pages deployment config. + // If you aren't using GitHub pages, you don't need these. + organizationName: 'hippo4j', // Usually your GitHub org/user name. + projectName: 'hippo4j.github.io', // Usually your repo name. + deploymentBranch: 'main', - // Even if you don't use internalization, you can use this field to set useful - // metadata like html lang. For example, if your site is Chinese, you may want - // to replace "en" with "zh-Hans". - i18n: { - defaultLocale: 'en', - locales: ['en', 'zh'], - localeConfigs: { - en: { - label: 'English', - direction: 'ltr', - }, - zh: { - label: '简体中文', - direction: 'ltr', - }, + // Even if you don't use internalization, you can use this field to set useful + // metadata like html lang. For example, if your site is Chinese, you may want + // to replace "en" with "zh-Hans". + i18n: { + defaultLocale: 'en', + locales: ['en', 'zh'], + localeConfigs: { + en: { + label: 'English', + direction: 'ltr', + }, + zh: { + label: '简体中文', + direction: 'ltr', + }, + }, }, - }, - presets: [ - [ - 'classic', - /** @type {import('@docusaurus/preset-classic').Options} */ - ({ - docs: { - sidebarPath: require.resolve('./sidebars.js'), - // Please change this to your repo. - // Remove this to remove the "edit this page" links. - sidebarCollapsed: false, - /*editUrl: 'https://github.com/longtai-cn',*/ - }, - blog: { - showReadingTime: true, - // Please change this to your repo. - // Remove this to remove the "edit this page" links. - editUrl: - 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', - }, - theme: { - customCss: require.resolve('./src/css/custom.css'), - }, - }), + presets: [ + [ + 'classic', + /** @type {import('@docusaurus/preset-classic').Options} */ + ({ + docs: { + sidebarPath: require.resolve('./sidebars.js'), + // Please change this to your repo. + // Remove this to remove the "edit this page" links. + sidebarCollapsed: false, + /*editUrl: 'https://github.com/longtai-cn',*/ + }, + blog: { + showReadingTime: true, + // Please change this to your repo. + // Remove this to remove the "edit this page" links. + editUrl: + 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', + }, + theme: { + customCss: require.resolve('./src/css/custom.css'), + }, + }), + ], ], - ], - plugins: [ - [ - '@docusaurus/plugin-content-docs', - { - id: 'community', - path: 'community', - routeBasePath: 'community', - sidebarPath: require.resolve('./sidebarsCommunity.js'), - }, + plugins: [ + [ + '@docusaurus/plugin-content-docs', + { + id: 'community', + path: 'community', + routeBasePath: 'community', + sidebarPath: require.resolve('./sidebarsCommunity.js'), + }, + ], ], - ], - themeConfig: + themeConfig: /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ - ({ - autoCollapseCategories: true, - announcementBar: { - id: 'announcementBar-1', // Increment on change - // content: `⭐️ If you like hippo4j, give it a star on Gitee, thanks.`, - // content: `⭐️ 如果您喜欢 hippo4j,请在 GiteeGitHub 上给它一个 star,谢谢!`, - content: `⭐️ 开源不易,如果 Hippo4j 对您有帮助,请在 GitHub 上给它一个 Star 🌟`, - // content: `👉 《小马哥的代码实战课》官方知识星球来啦!!!`, - }, - navbar: { - title: '', - logo: { - alt: 'Hippo4j 动态可观测线程池框架', - src: 'img/hippo4j.png', - }, - items: [ - { - type: 'docSidebar', - docId: 'intro', - position: 'left', - sidebarId: 'user_docs', - label: '文档', - }, - { - to: '/community/contributor-guide', - label: '社区', - position: 'left', - activeBaseRegex: `/community/`, - }, - /*{ to: "/team", label: "团队", position: "left" },*/ - { to: '/users', label: '采用公司', position: 'left' }, - { to: '/group', label: '加群沟通', position: 'left' }, - /*{to: '/blog', label: '博客', position: 'left'},*/ - { - href: 'http://console.hippo4j.cn/index.html', - label: '控制台样例', - position: 'left', - }, - { - href: 'https://gitee.com/opengoofy/congomall', - label: '👉 刚果商城', - position: 'left', - }, - { - type: 'docsVersionDropdown', - position: 'right', - dropdownActiveClassDisabled: true, - }, - - { type: 'localeDropdown', position: 'right' }, - /*{ - href: 'https://gitee.com/mabaiwancn/hippo4j', - label: 'Gitee', + ({ + autoCollapseCategories: true, + announcementBar: { + id: 'announcementBar-1', // Increment on change + // content: `⭐️ If you like hippo4j, give it a star on Gitee, thanks.`, + // content: `⭐️ 如果您喜欢 hippo4j,请在 GiteeGitHub 上给它一个 star,谢谢!`, + content: `⭐️ 开源不易,如果 Hippo4j 对您有帮助,请在 GitHub 上给它一个 Star 🌟`, + // content: `👉 《小马哥的代码实战课》官方知识星球来啦!!!`, + }, + navbar: { + title: '', + logo: { + alt: 'Hippo4j 动态可观测线程池框架', + src: 'img/hippo4j.png', + }, + items: [ + { + type: 'docSidebar', + docId: 'intro', + position: 'left', + sidebarId: 'user_docs', + label: '文档', + }, + { + to: '/community/contributor-guide', + label: '社区', + position: 'left', + activeBaseRegex: `/community/`, + }, + /*{ to: "/team", label: "团队", position: "left" },*/ + {to: '/users', label: '采用公司', position: 'left'}, + {to: '/group', label: '加群沟通', position: 'left'}, + /*{to: '/blog', label: '博客', position: 'left'},*/ + { + href: 'http://console.hippo4j.cn/index.html', + label: '控制台样例', + position: 'left', + }, + { + href: 'https://magestack.cn', + label: '🚀 拿个offer', + position: 'left', + }, + { + type: 'docsVersionDropdown', position: 'right', - },*/ - { - href: 'https://github.com/opengoofy/hippo4j', - className: 'header-github-link', - 'aria-label': 'GitHub repository', - position: 'right', - }, + dropdownActiveClassDisabled: true, + }, - /*{ + {type: 'localeDropdown', position: 'right'}, + /*{ + href: 'https://gitee.com/mabaiwancn/hippo4j', + label: 'Gitee', + position: 'right', + },*/ + { href: 'https://github.com/opengoofy/hippo4j', - label: 'GitHub', + className: 'header-github-link', + 'aria-label': 'GitHub repository', position: 'right', - },*/ - ], - }, - footer: { - style: 'dark', - links: [ - { - title: 'Docs', - items: [ - { - label: 'Intro', - to: '/docs/user_docs/intro', - }, - { - label: 'Config Mode', - to: '/docs/user_docs/getting_started/config/hippo4j-config-start', - }, - { - label: 'Server Mode', - to: '/docs/user_docs/getting_started/server/hippo4j-server-start', - }, - ], - }, - { - title: 'Community', - items: [ - { - label: 'Group', - href: 'https://hippo4j.cn/group', - }, - { - label: 'WeChat', - href: 'https://mp.weixin.qq.com/s/diVHYvwiuYH9aWpZDPc27g', - }, - ], - }, - { - title: 'More', - items: [ - { - label: 'Gitee', - href: 'https://gitee.com/opengoofy/hippo4j', - }, - { - label: 'GitHub', - href: 'https://github.com/opengoofy/hippo4j', - }, - ], - }, - { - title: 'Links', - items: [ - { - label: '书源', - href: 'https://bookyuan.cn/', - }, - { - label: '推广合作', - href: 'https://hippo4j.cn/docs/user_docs/other/operation', - }, - ], - }, - ], - copyright: `Copyright © 2021-2022 马丁版权所有 京ICP备2021038095号 + }, + + /*{ + href: 'https://github.com/opengoofy/hippo4j', + label: 'GitHub', + position: 'right', + },*/ + ], + }, + footer: { + style: 'dark', + links: [ + { + title: 'Docs', + items: [ + { + label: 'Intro', + to: '/docs/user_docs/intro', + }, + { + label: 'Config Mode', + to: '/docs/user_docs/getting_started/config/hippo4j-config-start', + }, + { + label: 'Server Mode', + to: '/docs/user_docs/getting_started/server/hippo4j-server-start', + }, + ], + }, + { + title: 'Community', + items: [ + { + label: 'Group', + href: 'https://hippo4j.cn/group', + }, + { + label: 'WeChat', + href: 'https://mp.weixin.qq.com/s/diVHYvwiuYH9aWpZDPc27g', + }, + ], + }, + { + title: 'More', + items: [ + { + label: 'Gitee', + href: 'https://gitee.com/opengoofy/hippo4j', + }, + { + label: 'GitHub', + href: 'https://github.com/opengoofy/hippo4j', + }, + ], + }, + { + title: 'Links', + items: [ + { + label: '推广合作', + href: 'https://hippo4j.cn/docs/user_docs/other/operation', + }, + ], + }, + ], + copyright: `Copyright © 2021-2023 马丁版权所有 京ICP备2021038095号 `, - }, - prism: { - theme: lightCodeTheme, - darkTheme: darkCodeTheme, - additionalLanguages: ['java'], - }, - }), + }, + prism: { + theme: lightCodeTheme, + darkTheme: darkCodeTheme, + additionalLanguages: ['java'], + }, + }), }; module.exports = config; diff --git a/docs/i18n/zh/docusaurus-plugin-content-pages/users.md b/docs/i18n/zh/docusaurus-plugin-content-pages/users.md index f06de39a..61618305 100644 --- a/docs/i18n/zh/docusaurus-plugin-content-pages/users.md +++ b/docs/i18n/zh/docusaurus-plugin-content-pages/users.md @@ -5,7 +5,7 @@ title: 采用公司 ## 谁在使用 Hippo4j -共计 39+ 家公司生产接入 Hippo4j,按照公司登记时间排序。 +共计 42+ 家公司生产接入 Hippo4j,按照公司登记时间排序。 - [身边云](https://serviceshare.com) - [思派健康科技](https://www.medbanks.cn) @@ -46,6 +46,9 @@ title: 采用公司 - [广联达科技股份有限公司](https://www.glodon.com) - [天健联创控股集团有限公司](https://www.tjlc.com.cn) - [知乎](https://www.zhihu.com/) +- [广东谷通科技有限公司](https://www.duofriend.com) +- [成都全域智旅科技有限公司](http://qyzl.com) +- [深圳市华云中盛科技股份有限公司](http://www.hua-cloud.cn) ## 登记 diff --git a/docs/src/pages/users.md b/docs/src/pages/users.md index f06de39a..61618305 100644 --- a/docs/src/pages/users.md +++ b/docs/src/pages/users.md @@ -5,7 +5,7 @@ title: 采用公司 ## 谁在使用 Hippo4j -共计 39+ 家公司生产接入 Hippo4j,按照公司登记时间排序。 +共计 42+ 家公司生产接入 Hippo4j,按照公司登记时间排序。 - [身边云](https://serviceshare.com) - [思派健康科技](https://www.medbanks.cn) @@ -46,6 +46,9 @@ title: 采用公司 - [广联达科技股份有限公司](https://www.glodon.com) - [天健联创控股集团有限公司](https://www.tjlc.com.cn) - [知乎](https://www.zhihu.com/) +- [广东谷通科技有限公司](https://www.duofriend.com) +- [成都全域智旅科技有限公司](http://qyzl.com) +- [深圳市华云中盛科技股份有限公司](http://www.hua-cloud.cn) ## 登记 From abe77a7a9872d45610997d166bee58467dd25e26 Mon Sep 17 00:00:00 2001 From: shizi <137272795+shizi327@users.noreply.github.com> Date: Sun, 30 Jul 2023 15:33:35 +0800 Subject: [PATCH 05/10] Refactoring throws an exception when the newly set number of core threads exceeds the maximum number of threads (#1409) Co-authored-by: 2590965087@qq.com <2590968087@qq.com> --- .../support/ThreadPoolExecutorUtilTest.java | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 infra/common/src/test/java/cn/hippo4j/common/executor/support/ThreadPoolExecutorUtilTest.java diff --git a/infra/common/src/test/java/cn/hippo4j/common/executor/support/ThreadPoolExecutorUtilTest.java b/infra/common/src/test/java/cn/hippo4j/common/executor/support/ThreadPoolExecutorUtilTest.java new file mode 100644 index 00000000..97383037 --- /dev/null +++ b/infra/common/src/test/java/cn/hippo4j/common/executor/support/ThreadPoolExecutorUtilTest.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.executor.support; + +import cn.hippo4j.common.toolkit.ThreadPoolExecutorUtil; +import lombok.extern.slf4j.Slf4j; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * Thread pool executor util test + */ +@Slf4j +public class ThreadPoolExecutorUtilTest { + + private ThreadPoolExecutor executor; + private int corePoolSize; + private int maxPoolSize; + + @Before + public void testSafeSetPoolSize() { + corePoolSize = 2; + maxPoolSize = 4; + executor = new ThreadPoolExecutor( + corePoolSize, + maxPoolSize, + 1L, + TimeUnit.SECONDS, + new ArrayBlockingQueue<>(10) + ); + } + + @Test + public void testEquals(){ + // Test when the new core pool size equals the original maximum pool size. + int newCorePoolSize1 = maxPoolSize; + int newMaxPoolSize1 = 6; + ThreadPoolExecutorUtil.safeSetPoolSize(executor, newCorePoolSize1, newMaxPoolSize1); + Assert.assertEquals(newCorePoolSize1, executor.getCorePoolSize()); + Assert.assertEquals(newMaxPoolSize1, executor.getMaximumPoolSize()); + } + + @Test + public void testGreater(){ + // Test when the new core pool size is greater than the original maximum pool size. + int newCorePoolSize2 = 8; + int newMaxPoolSize2 = 10; + ThreadPoolExecutorUtil.safeSetPoolSize(executor, newCorePoolSize2, newMaxPoolSize2); + Assert.assertEquals(newCorePoolSize2, executor.getCorePoolSize()); + Assert.assertEquals(newMaxPoolSize2, executor.getMaximumPoolSize()); + } + + @Test + public void testLess(){ + // Test when the new core pool size is less than the original maximum pool size. + int newCorePoolSize3 = 3; + int newMaxPoolSize3 = 5; + ThreadPoolExecutorUtil.safeSetPoolSize(executor, newCorePoolSize3, newMaxPoolSize3); + Assert.assertEquals(newCorePoolSize3, executor.getCorePoolSize()); + Assert.assertEquals(newMaxPoolSize3, executor.getMaximumPoolSize()); + } + + @Test + public void testException(){ + // Test when the new core pool size is greater than the new maximum pool size, which should throw an IllegalArgumentException. + int newCorePoolSize4 = 6; + int newMaxPoolSize4 = 4; + try { + ThreadPoolExecutorUtil.safeSetPoolSize(executor, newCorePoolSize4, newMaxPoolSize4); + } catch (IllegalArgumentException e) { + // Expected to throw an exception. + Assert.assertEquals("newCorePoolSize must be smaller than newMaximumPoolSize", e.getMessage()); + log.error("newCorePoolSize must be smaller than newMaximumPoolSize;{}",e.getMessage()); + } + } +} From 6f3a6e0cc2377238477f0d2e4c14b5283f529ea3 Mon Sep 17 00:00:00 2001 From: Luke Liang <39796629+LukeLiang@users.noreply.github.com> Date: Mon, 31 Jul 2023 11:47:37 +0800 Subject: [PATCH 06/10] =?UTF-8?q?Replace=20the=20buffer=20pool=20type=20fr?= =?UTF-8?q?om=20ArrayBlockingQueue=20to=20LinkedBlockin=E2=80=A6=20(#1411)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Replace the buffer pool type from ArrayBlockingQueue to LinkedBlockingQueue type * Import LinkedBlockingQueue package --- .../springboot/starter/monitor/ReportingEventExecutor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/starters/threadpool/server/src/main/java/cn/hippo4j/springboot/starter/monitor/ReportingEventExecutor.java b/starters/threadpool/server/src/main/java/cn/hippo4j/springboot/starter/monitor/ReportingEventExecutor.java index 0038c62d..884aeaa7 100644 --- a/starters/threadpool/server/src/main/java/cn/hippo4j/springboot/starter/monitor/ReportingEventExecutor.java +++ b/starters/threadpool/server/src/main/java/cn/hippo4j/springboot/starter/monitor/ReportingEventExecutor.java @@ -45,6 +45,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -136,7 +137,7 @@ public class ReportingEventExecutor implements Runnable, CommandLineRunner, Disp properties.getCollectInterval(), TimeUnit.MILLISECONDS); Integer bufferSize = properties.getTaskBufferSize(); - messageCollectVessel = new ArrayBlockingQueue(bufferSize); + messageCollectVessel = new LinkedBlockingQueue(bufferSize); // Get all data collection components, currently only historical operation data collection. collectors = ApplicationContextHolder.getBeansOfType(Collector.class); // Start reporting monitoring data thread. From 1b744ac91fb0ad661a32920c371c434b758103a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9F=A9=E6=96=B0=E9=BE=99?= <100343863+Han-Xinlong@users.noreply.github.com> Date: Mon, 31 Jul 2023 13:06:00 +0800 Subject: [PATCH 07/10] Service exception test (#1410) * hxl- commit - 7-29 * Service exception test * Service exception test update --- .../common/base/ServiceExceptionTest.java | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 threadpool/server/common/src/test/java/cn/hippo4j/server/common/base/ServiceExceptionTest.java diff --git a/threadpool/server/common/src/test/java/cn/hippo4j/server/common/base/ServiceExceptionTest.java b/threadpool/server/common/src/test/java/cn/hippo4j/server/common/base/ServiceExceptionTest.java new file mode 100644 index 00000000..fc55129b --- /dev/null +++ b/threadpool/server/common/src/test/java/cn/hippo4j/server/common/base/ServiceExceptionTest.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.server.common.base; + +import cn.hippo4j.common.toolkit.Assert; +import cn.hippo4j.server.common.base.exception.ErrorCode; +import cn.hippo4j.server.common.base.exception.ErrorCodeEnum; +import cn.hippo4j.server.common.base.exception.ServiceException; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import org.checkerframework.checker.units.qual.A; +import org.junit.jupiter.api.Test; +import java.util.Objects; + +/** + * Service exception test + */ +public class ServiceExceptionTest { + + @Test + public void ServiceExceptionTest1(){ + ServiceException serviceException = new ServiceException(); + Assert.isTrue(Objects.equals(serviceException.getErrorCode().getCode(), "3")); + Assert.isTrue(Objects.equals(serviceException.getMessage(), "SERVICE_ERROR")); + } + + @Test + public void ServiceExceptionTest2(){ + ErrorCode errorCode = ErrorCodeEnum.LOGIN_TIMEOUT; + ServiceException serviceException = new ServiceException(errorCode); + Assert.isTrue(Objects.equals(serviceException.getErrorCode().getCode(), ErrorCodeEnum.LOGIN_TIMEOUT.getCode())); + Assert.isTrue(Objects.equals(serviceException.getMessage(), ErrorCodeEnum.LOGIN_TIMEOUT.getMessage())); + } + + @Test + public void ServiceExceptionTest3(){ + String message = ErrorCodeEnum.SERVICE_ERROR.getMessage(); + ServiceException serviceException = new ServiceException(message); + Assert.isTrue(Objects.equals(serviceException.getMessage(), message)); + } + + @Test + public void ServiceExceptionTest4(){ + Throwable cause = new Throwable(); + ServiceException serviceException = new ServiceException(cause); + Assert.isTrue(Objects.equals(serviceException.getCause().getMessage(), cause.getMessage())); + } + + @Test + public void ServiceExceptionTest5(){ + String message = ErrorCodeEnum.SERVICE_ERROR.getMessage(); + Throwable cause = new Throwable(); + ServiceException serviceException = new ServiceException(message, cause); + Assert.isTrue(Objects.equals(serviceException.getCause().getMessage(), cause.getMessage())); + Assert.isTrue(Objects.equals(serviceException.getMessage(), message)); + } + + @Test + public void ServiceExceptionTest6(){ + String message = ErrorCodeEnum.SERVICE_ERROR.getMessage(); + Throwable cause = new Throwable(); + ServiceException serviceException = new ServiceException(cause, message); + Assert.isTrue(Objects.equals(serviceException.getCause().getMessage(), cause.getMessage())); + Assert.isTrue(Objects.equals(serviceException.getMessage(), message)); + } + + @Test + public void ServiceExceptionTest7(){ + Throwable cause = new Throwable(); + ErrorCode errorCode = ErrorCodeEnum.LOGIN_TIMEOUT; + ServiceException serviceException = new ServiceException(cause, errorCode); + Assert.isTrue(Objects.equals(serviceException.getCause().getMessage(), cause.getMessage())); + Assert.isTrue(Objects.equals(serviceException.getErrorCode().getCode(), ErrorCodeEnum.LOGIN_TIMEOUT.getCode())); + } + + @Test + public void ServiceExceptionTest8(){ + Throwable cause = new Throwable(); + ErrorCode errorCode = ErrorCodeEnum.LOGIN_TIMEOUT; + String message = ErrorCodeEnum.SERVICE_ERROR.getMessage(); + ServiceException serviceException = new ServiceException(message, cause, errorCode); + Assert.isTrue(Objects.equals(serviceException.getCause().getMessage(), cause.getMessage())); + Assert.isTrue(Objects.equals(serviceException.getErrorCode().getCode(), ErrorCodeEnum.LOGIN_TIMEOUT.getCode())); + Assert.isTrue(Objects.equals(serviceException.getMessage(), message)); + } +} From 1e95ce8fb2936b2514d07eb2fdfa6252b1afe912 Mon Sep 17 00:00:00 2001 From: zjHe <34431616+zjHe@users.noreply.github.com> Date: Tue, 1 Aug 2023 21:17:46 +0800 Subject: [PATCH 08/10] @EnableDynamicThreadPool controls MicrometerMonitorAutoConfiguration (#1413) --- .../support/ThreadPoolExecutorUtilTest.java | 13 ++++++------- .../MicrometerMonitorAutoConfiguration.java | 1 - .../AdaptedThreadPoolDestroyPostProcessor.java | 4 ++-- ...dapterThreadPoolMicrometerMonitorHandler.java | 4 +++- .../server/common/base/ServiceExceptionTest.java | 16 ++++++++-------- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/infra/common/src/test/java/cn/hippo4j/common/executor/support/ThreadPoolExecutorUtilTest.java b/infra/common/src/test/java/cn/hippo4j/common/executor/support/ThreadPoolExecutorUtilTest.java index 97383037..88f523bb 100644 --- a/infra/common/src/test/java/cn/hippo4j/common/executor/support/ThreadPoolExecutorUtilTest.java +++ b/infra/common/src/test/java/cn/hippo4j/common/executor/support/ThreadPoolExecutorUtilTest.java @@ -45,12 +45,11 @@ public class ThreadPoolExecutorUtilTest { maxPoolSize, 1L, TimeUnit.SECONDS, - new ArrayBlockingQueue<>(10) - ); + new ArrayBlockingQueue<>(10)); } @Test - public void testEquals(){ + public void testEquals() { // Test when the new core pool size equals the original maximum pool size. int newCorePoolSize1 = maxPoolSize; int newMaxPoolSize1 = 6; @@ -60,7 +59,7 @@ public class ThreadPoolExecutorUtilTest { } @Test - public void testGreater(){ + public void testGreater() { // Test when the new core pool size is greater than the original maximum pool size. int newCorePoolSize2 = 8; int newMaxPoolSize2 = 10; @@ -70,7 +69,7 @@ public class ThreadPoolExecutorUtilTest { } @Test - public void testLess(){ + public void testLess() { // Test when the new core pool size is less than the original maximum pool size. int newCorePoolSize3 = 3; int newMaxPoolSize3 = 5; @@ -80,7 +79,7 @@ public class ThreadPoolExecutorUtilTest { } @Test - public void testException(){ + public void testException() { // Test when the new core pool size is greater than the new maximum pool size, which should throw an IllegalArgumentException. int newCorePoolSize4 = 6; int newMaxPoolSize4 = 4; @@ -89,7 +88,7 @@ public class ThreadPoolExecutorUtilTest { } catch (IllegalArgumentException e) { // Expected to throw an exception. Assert.assertEquals("newCorePoolSize must be smaller than newMaximumPoolSize", e.getMessage()); - log.error("newCorePoolSize must be smaller than newMaximumPoolSize;{}",e.getMessage()); + log.error("newCorePoolSize must be smaller than newMaximumPoolSize;{}", e.getMessage()); } } } diff --git a/starters/threadpool/monitor/hippo4j-spring-boot-starter-monitor-micrometer/src/main/java/cn/hippo4j/springboot/starter/monitor/micrometer/MicrometerMonitorAutoConfiguration.java b/starters/threadpool/monitor/hippo4j-spring-boot-starter-monitor-micrometer/src/main/java/cn/hippo4j/springboot/starter/monitor/micrometer/MicrometerMonitorAutoConfiguration.java index 1eb7b70b..73834bb8 100644 --- a/starters/threadpool/monitor/hippo4j-spring-boot-starter-monitor-micrometer/src/main/java/cn/hippo4j/springboot/starter/monitor/micrometer/MicrometerMonitorAutoConfiguration.java +++ b/starters/threadpool/monitor/hippo4j-spring-boot-starter-monitor-micrometer/src/main/java/cn/hippo4j/springboot/starter/monitor/micrometer/MicrometerMonitorAutoConfiguration.java @@ -27,7 +27,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; /** * Micrometer monitor auto configuration. diff --git a/starters/threadpool/server/src/main/java/cn/hippo4j/springboot/starter/support/AdaptedThreadPoolDestroyPostProcessor.java b/starters/threadpool/server/src/main/java/cn/hippo4j/springboot/starter/support/AdaptedThreadPoolDestroyPostProcessor.java index ce425560..9b60a4f6 100644 --- a/starters/threadpool/server/src/main/java/cn/hippo4j/springboot/starter/support/AdaptedThreadPoolDestroyPostProcessor.java +++ b/starters/threadpool/server/src/main/java/cn/hippo4j/springboot/starter/support/AdaptedThreadPoolDestroyPostProcessor.java @@ -81,14 +81,14 @@ public class AdaptedThreadPoolDestroyPostProcessor implements DestructionAwareBe @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { // forked default implementation from spring-beans-5.1.14.RELEASE.jar - // org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization + // org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { // forked default implementation from spring-beans-5.1.14.RELEASE.jar - // org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization + // org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization return bean; } diff --git a/threadpool/monitor/micrometer/src/main/java/cn/hippo4j/monitor/micrometer/AdapterThreadPoolMicrometerMonitorHandler.java b/threadpool/monitor/micrometer/src/main/java/cn/hippo4j/monitor/micrometer/AdapterThreadPoolMicrometerMonitorHandler.java index ea993663..fe28dc21 100644 --- a/threadpool/monitor/micrometer/src/main/java/cn/hippo4j/monitor/micrometer/AdapterThreadPoolMicrometerMonitorHandler.java +++ b/threadpool/monitor/micrometer/src/main/java/cn/hippo4j/monitor/micrometer/AdapterThreadPoolMicrometerMonitorHandler.java @@ -58,7 +58,9 @@ public class AdapterThreadPoolMicrometerMonitorHandler extends AbstractAdapterTh Tag.of(APPLICATION_NAME_TAG, applicationName)); Metrics.gauge(metricName("core.size"), tags, threadPoolAdapterState, ThreadPoolAdapterState::getCoreSize); Metrics.gauge(metricName("maximum.size"), tags, threadPoolAdapterState, ThreadPoolAdapterState::getMaximumSize); - Metrics.gauge(metricName("queue.capacity"), tags, threadPoolAdapterState, ThreadPoolAdapterState::getBlockingQueueCapacity); + if (threadPoolAdapterState.getBlockingQueueCapacity() != null) { + Metrics.gauge(metricName("queue.capacity"), tags, threadPoolAdapterState, ThreadPoolAdapterState::getBlockingQueueCapacity); + } } private String metricName(String name) { diff --git a/threadpool/server/common/src/test/java/cn/hippo4j/server/common/base/ServiceExceptionTest.java b/threadpool/server/common/src/test/java/cn/hippo4j/server/common/base/ServiceExceptionTest.java index fc55129b..833afe1b 100644 --- a/threadpool/server/common/src/test/java/cn/hippo4j/server/common/base/ServiceExceptionTest.java +++ b/threadpool/server/common/src/test/java/cn/hippo4j/server/common/base/ServiceExceptionTest.java @@ -32,14 +32,14 @@ import java.util.Objects; public class ServiceExceptionTest { @Test - public void ServiceExceptionTest1(){ + public void ServiceExceptionTest1() { ServiceException serviceException = new ServiceException(); Assert.isTrue(Objects.equals(serviceException.getErrorCode().getCode(), "3")); Assert.isTrue(Objects.equals(serviceException.getMessage(), "SERVICE_ERROR")); } @Test - public void ServiceExceptionTest2(){ + public void ServiceExceptionTest2() { ErrorCode errorCode = ErrorCodeEnum.LOGIN_TIMEOUT; ServiceException serviceException = new ServiceException(errorCode); Assert.isTrue(Objects.equals(serviceException.getErrorCode().getCode(), ErrorCodeEnum.LOGIN_TIMEOUT.getCode())); @@ -47,21 +47,21 @@ public class ServiceExceptionTest { } @Test - public void ServiceExceptionTest3(){ + public void ServiceExceptionTest3() { String message = ErrorCodeEnum.SERVICE_ERROR.getMessage(); ServiceException serviceException = new ServiceException(message); Assert.isTrue(Objects.equals(serviceException.getMessage(), message)); } @Test - public void ServiceExceptionTest4(){ + public void ServiceExceptionTest4() { Throwable cause = new Throwable(); ServiceException serviceException = new ServiceException(cause); Assert.isTrue(Objects.equals(serviceException.getCause().getMessage(), cause.getMessage())); } @Test - public void ServiceExceptionTest5(){ + public void ServiceExceptionTest5() { String message = ErrorCodeEnum.SERVICE_ERROR.getMessage(); Throwable cause = new Throwable(); ServiceException serviceException = new ServiceException(message, cause); @@ -70,7 +70,7 @@ public class ServiceExceptionTest { } @Test - public void ServiceExceptionTest6(){ + public void ServiceExceptionTest6() { String message = ErrorCodeEnum.SERVICE_ERROR.getMessage(); Throwable cause = new Throwable(); ServiceException serviceException = new ServiceException(cause, message); @@ -79,7 +79,7 @@ public class ServiceExceptionTest { } @Test - public void ServiceExceptionTest7(){ + public void ServiceExceptionTest7() { Throwable cause = new Throwable(); ErrorCode errorCode = ErrorCodeEnum.LOGIN_TIMEOUT; ServiceException serviceException = new ServiceException(cause, errorCode); @@ -88,7 +88,7 @@ public class ServiceExceptionTest { } @Test - public void ServiceExceptionTest8(){ + public void ServiceExceptionTest8() { Throwable cause = new Throwable(); ErrorCode errorCode = ErrorCodeEnum.LOGIN_TIMEOUT; String message = ErrorCodeEnum.SERVICE_ERROR.getMessage(); From 0a08f09e851d5c0982b1943dc8d1cfaae118e4d8 Mon Sep 17 00:00:00 2001 From: GRL-bxy <77558077+GRL-bxy@users.noreply.github.com> Date: Thu, 3 Aug 2023 22:09:39 +0800 Subject: [PATCH 09/10] =?UTF-8?q?fix=EF=BC=9Acreate=20thread=20poll=20cont?= =?UTF-8?q?ent=20not=20change=20(#1416)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- threadpool/console/src/views/hippo4j/threadpool/index.vue | 1 + threadpool/console/src/views/login/index.vue | 1 + 2 files changed, 2 insertions(+) diff --git a/threadpool/console/src/views/hippo4j/threadpool/index.vue b/threadpool/console/src/views/hippo4j/threadpool/index.vue index 87e4aed3..dfa0e21b 100755 --- a/threadpool/console/src/views/hippo4j/threadpool/index.vue +++ b/threadpool/console/src/views/hippo4j/threadpool/index.vue @@ -744,6 +744,7 @@ export default { } else if (value === 5) { this.temp.capacity = 2147483647; } + this.$forceUpdate(); }, tenantSelectList() { diff --git a/threadpool/console/src/views/login/index.vue b/threadpool/console/src/views/login/index.vue index 66ce2387..c422fae3 100755 --- a/threadpool/console/src/views/login/index.vue +++ b/threadpool/console/src/views/login/index.vue @@ -128,6 +128,7 @@ export default { if (hostname === 'console.hippo4j.cn') { this.loginForm.username = 'hippo4j'; this.loginForm.password = 'hippo4j'; + this.rememberMe = 1; } console.log(hostname); }, From de703cfca142d83cbfb127fa7ae78d0918790523 Mon Sep 17 00:00:00 2001 From: Pan_Yujie <102404203+Pan-YuJie@users.noreply.github.com> Date: Tue, 15 Aug 2023 16:42:16 +0800 Subject: [PATCH 10/10] Feature: server add Ldap user authentication (#1392) --- threadpool/server/auth/pom.xml | 4 + .../auth/config/GlobalSecurityConfig.java | 39 ++++- .../auth/config/LdapConfiguration.java | 72 ++++++++ .../auth/filter/JWTAuthenticationFilter.java | 18 +- .../auth/filter/LdapAuthenticationFilter.java | 155 ++++++++++++++++++ .../cn/hippo4j/auth/model/LdapUserInfo.java | 39 +++++ .../cn/hippo4j/auth/service/LdapService.java | 28 ++++ .../auth/service/impl/LdapServiceImpl.java | 72 ++++++++ .../impl/LdapUserDetailsServiceImpl.java | 115 +++++++++++++ .../service/impl/UserDetailsServiceImpl.java | 15 +- .../toolkit/BCryptPasswordEncoderTest.java | 20 +++ .../src/main/resources/ldap-back.properties | 14 ++ 12 files changed, 584 insertions(+), 7 deletions(-) create mode 100644 threadpool/server/auth/src/main/java/cn/hippo4j/auth/config/LdapConfiguration.java create mode 100644 threadpool/server/auth/src/main/java/cn/hippo4j/auth/filter/LdapAuthenticationFilter.java create mode 100644 threadpool/server/auth/src/main/java/cn/hippo4j/auth/model/LdapUserInfo.java create mode 100644 threadpool/server/auth/src/main/java/cn/hippo4j/auth/service/LdapService.java create mode 100644 threadpool/server/auth/src/main/java/cn/hippo4j/auth/service/impl/LdapServiceImpl.java create mode 100644 threadpool/server/auth/src/main/java/cn/hippo4j/auth/service/impl/LdapUserDetailsServiceImpl.java create mode 100644 threadpool/server/auth/src/test/java/cn/hippo4j/auth/toolkit/BCryptPasswordEncoderTest.java create mode 100644 threadpool/server/bootstrap/src/main/resources/ldap-back.properties diff --git a/threadpool/server/auth/pom.xml b/threadpool/server/auth/pom.xml index ce8d8175..aff6a5d5 100644 --- a/threadpool/server/auth/pom.xml +++ b/threadpool/server/auth/pom.xml @@ -62,5 +62,9 @@ hippo4j-threadpool-server-common ${project.version} + + org.springframework.boot + spring-boot-starter-data-ldap + diff --git a/threadpool/server/auth/src/main/java/cn/hippo4j/auth/config/GlobalSecurityConfig.java b/threadpool/server/auth/src/main/java/cn/hippo4j/auth/config/GlobalSecurityConfig.java index b239b42c..83b3d1ca 100644 --- a/threadpool/server/auth/src/main/java/cn/hippo4j/auth/config/GlobalSecurityConfig.java +++ b/threadpool/server/auth/src/main/java/cn/hippo4j/auth/config/GlobalSecurityConfig.java @@ -20,6 +20,7 @@ package cn.hippo4j.auth.config; import cn.hippo4j.auth.constant.Constants; import cn.hippo4j.auth.filter.JWTAuthenticationFilter; import cn.hippo4j.auth.filter.JWTAuthorizationFilter; +import cn.hippo4j.auth.filter.LdapAuthenticationFilter; import cn.hippo4j.auth.security.JwtTokenManager; import cn.hippo4j.auth.service.impl.UserDetailsServiceImpl; import org.springframework.beans.factory.annotation.Value; @@ -28,6 +29,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.BeanIds; +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.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; @@ -54,9 +56,12 @@ public class GlobalSecurityConfig extends WebSecurityConfigurerAdapter { @Value("${hippo4j.core.auth.enabled:true}") private Boolean enableAuthentication; - @Resource + @Resource(name = "userDetailsServiceImpl") private UserDetailsService userDetailsService; + @Resource(name = "ldapUserDetailsServiceImpl") + private UserDetailsService ldapUserDetailsService; + @Resource private JwtTokenManager tokenManager; @@ -93,7 +98,9 @@ public class GlobalSecurityConfig extends WebSecurityConfigurerAdapter { .antMatchers("/static/**", "/index.html", "/favicon.ico", "/avatar.jpg").permitAll() .antMatchers("/doc.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs").anonymous() .and() - .addFilter(new JWTAuthenticationFilter(authenticationManager())) + // .addFilter(new JWTAuthenticationFilter(authenticationManager())).authenticationProvider(authenticationProvider()) + .addFilter(JWTAuthenticationFilter()).authenticationProvider(ldapAuthenticationProvider()) + .addFilter(LdapAuthenticationFilter()).authenticationProvider(ldapAuthenticationProvider()) .addFilter(new JWTAuthorizationFilter(tokenManager, authenticationManager())) .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); disableAuthenticationIfNeeded(http); @@ -106,6 +113,20 @@ public class GlobalSecurityConfig extends WebSecurityConfigurerAdapter { web.ignoring().antMatchers(ignores); } + private LdapAuthenticationFilter LdapAuthenticationFilter() throws Exception { + LdapAuthenticationFilter filter = new LdapAuthenticationFilter(authenticationManager()); + filter.setLdapUserDetailsService(ldapUserDetailsService); + filter.setAuthenticationManager(authenticationManagerBean()); + return filter; + } + + private JWTAuthenticationFilter JWTAuthenticationFilter() throws Exception { + JWTAuthenticationFilter filter = new JWTAuthenticationFilter(authenticationManager()); + filter.setLdapUserDetailsService(userDetailsService); + filter.setAuthenticationManager(authenticationManagerBean()); + return filter; + } + /** * Injection DaoAuthenticationProvider * Modify hideUserNotFoundExceptions initial value to false @@ -120,6 +141,20 @@ public class GlobalSecurityConfig extends WebSecurityConfigurerAdapter { return provider; } + @Bean + public DaoAuthenticationProvider ldapAuthenticationProvider() { + DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); + authProvider.setUserDetailsService(ldapUserDetailsService); + authProvider.setPasswordEncoder(bCryptPasswordEncoder()); + return authProvider; + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.authenticationProvider(authenticationProvider()) + .authenticationProvider(ldapAuthenticationProvider()); + } + private void disableAuthenticationIfNeeded(HttpSecurity http) throws Exception { if (Boolean.FALSE.equals(enableAuthentication)) { http.authorizeRequests().antMatchers("/hippo4j/v1/cs/**").permitAll(); diff --git a/threadpool/server/auth/src/main/java/cn/hippo4j/auth/config/LdapConfiguration.java b/threadpool/server/auth/src/main/java/cn/hippo4j/auth/config/LdapConfiguration.java new file mode 100644 index 00000000..1932878d --- /dev/null +++ b/threadpool/server/auth/src/main/java/cn/hippo4j/auth/config/LdapConfiguration.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.auth.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.ldap.core.LdapTemplate; +import org.springframework.ldap.core.support.LdapContextSource; + +import java.util.HashMap; +import java.util.Map; + +/** + * Ldap config. + */ +@Configuration +public class LdapConfiguration { + + private LdapTemplate ldapTemplate; + + @Value("${spring.ldap.urls:}") + private String url; + + @Value("${spring.ldap.base:}") + private String base; + + @Value("${spring.ldap.embedded.credential.username:}") + private String username; + + @Value("${spring.ldap.embedded.credential.password:}") + private String password; + + @Bean + public LdapContextSource contextSource() { + LdapContextSource contextSource = new LdapContextSource(); + Map config = new HashMap<>(10); + contextSource.setUrl(url); + contextSource.setBase(base); + contextSource.setUserDn(username); + contextSource.setPassword(password); + // fix garbled characters + config.put("java.naming.ldap.attributes.binary", "objectGUID"); + + contextSource.setPooled(true); + contextSource.setBaseEnvironmentProperties(config); + return contextSource; + } + + @Bean + public LdapTemplate ldapTemplate() { + if (null == ldapTemplate) { + ldapTemplate = new LdapTemplate(contextSource()); + } + return ldapTemplate; + } +} diff --git a/threadpool/server/auth/src/main/java/cn/hippo4j/auth/filter/JWTAuthenticationFilter.java b/threadpool/server/auth/src/main/java/cn/hippo4j/auth/filter/JWTAuthenticationFilter.java index 408aa3d4..d9f270b5 100644 --- a/threadpool/server/auth/src/main/java/cn/hippo4j/auth/filter/JWTAuthenticationFilter.java +++ b/threadpool/server/auth/src/main/java/cn/hippo4j/auth/filter/JWTAuthenticationFilter.java @@ -25,23 +25,25 @@ import cn.hippo4j.auth.toolkit.ReturnT; import cn.hippo4j.common.toolkit.JSONUtil; import cn.hippo4j.server.common.base.Results; import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.core.codec.DecodingException; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; import javax.servlet.FilterChain; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.security.GeneralSecurityException; -import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -60,11 +62,18 @@ public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilte private final ThreadLocal rememberMe = new ThreadLocal(); + private UserDetailsService userDetailsService; + public JWTAuthenticationFilter(AuthenticationManager authenticationManager) { this.authenticationManager = authenticationManager; super.setFilterProcessesUrl(BASE_PATH + "/auth/login"); } + public void setLdapUserDetailsService(UserDetailsService userDetailsServiceImpl) { + this.userDetailsService = userDetailsServiceImpl; + } + + @SneakyThrows @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { @@ -78,8 +87,9 @@ public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilte request.setAttribute("loginUser", loginUser); rememberMe.set(loginUser.getRememberMe()); - authenticate = authenticationManager.authenticate( - new UsernamePasswordAuthenticationToken(loginUser.getUsername(), loginUser.getPassword(), new ArrayList())); + UserDetails userDetails = userDetailsService.loadUserByUsername(loginUser.getUsername()); + authenticate = new PreAuthenticatedAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + } catch (GeneralSecurityException e) { log.warn("Password decode exception: {}", e.getMessage()); throw new DecodingException(e.getMessage()); diff --git a/threadpool/server/auth/src/main/java/cn/hippo4j/auth/filter/LdapAuthenticationFilter.java b/threadpool/server/auth/src/main/java/cn/hippo4j/auth/filter/LdapAuthenticationFilter.java new file mode 100644 index 00000000..9ce982a3 --- /dev/null +++ b/threadpool/server/auth/src/main/java/cn/hippo4j/auth/filter/LdapAuthenticationFilter.java @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.auth.filter; + +import cn.hippo4j.auth.model.biz.user.JwtUser; +import cn.hippo4j.auth.model.biz.user.LoginUser; +import cn.hippo4j.auth.toolkit.AESUtil; +import cn.hippo4j.auth.toolkit.JwtTokenUtil; +import cn.hippo4j.auth.toolkit.ReturnT; +import cn.hippo4j.common.toolkit.JSONUtil; +import cn.hippo4j.server.common.base.Results; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.AuthenticationServiceException; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; + +import javax.servlet.FilterChain; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import static cn.hippo4j.auth.constant.Constants.SPLIT_COMMA; +import static cn.hippo4j.common.constant.Constants.BASE_PATH; +import static cn.hippo4j.common.constant.Constants.MAP_INITIAL_CAPACITY; + +/** + * Ldap Filter + */ +@Slf4j +public class LdapAuthenticationFilter extends UsernamePasswordAuthenticationFilter { + + private final ThreadLocal rememberMe = new ThreadLocal<>(); + + private UserDetailsService ldapUserDetailsService; + + public void setLdapUserDetailsService(UserDetailsService ldapUserDetailsServiceImpl) { + this.ldapUserDetailsService = ldapUserDetailsServiceImpl; + } + + public LdapAuthenticationFilter(AuthenticationManager authenticationManager) { + super.setFilterProcessesUrl(BASE_PATH + "/auth/ldap/login"); + } + + /** + * Whether it's just the post way + */ + private boolean postOnly = true; + + + /** + * filter obtains the username and password of LDAP and assembles it on the token. + * Then give the token for authorization + */ + @Override + public Authentication attemptAuthentication(HttpServletRequest request + , HttpServletResponse response) throws AuthenticationException { + if (postOnly && !"POST".equals(request.getMethod())) { + throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); + } else { + // Get logged in information from the input stream. + Authentication authenticate = null; + try { + LoginUser loginUser = new ObjectMapper().readValue(request.getInputStream(), LoginUser.class); + String key = new StringBuffer(loginUser.getTag()).reverse().toString(); + String password = AESUtil.decrypt(loginUser.getPassword(), key); + loginUser.setPassword(password); + request.setAttribute("loginUser", loginUser); + rememberMe.set(loginUser.getRememberMe()); + // ldap validated + UserDetails userDetails = ldapUserDetailsService.loadUserByUsername(loginUser.getUsername()); + authenticate = new PreAuthenticatedAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + } catch (UsernameNotFoundException e) { + log.debug("User {} not found", e.getMessage()); + throw e; + } catch (BadCredentialsException e) { + log.debug("Bad credentials exception: {}", e.getMessage()); + throw e; + } catch (Exception e) { + log.debug("Attempt authentication error", e); + } + return authenticate; + } + } + + @Override + protected void successfulAuthentication(HttpServletRequest request, + HttpServletResponse response, + FilterChain chain, + Authentication authResult) throws IOException { + try { + JwtUser jwtUser = (JwtUser) authResult.getPrincipal(); + boolean isRemember = rememberMe.get() == 1; + String role = ""; + Collection authorities = jwtUser.getAuthorities(); + for (GrantedAuthority authority : authorities) { + role = authority.getAuthority(); + } + String token = JwtTokenUtil.createToken(jwtUser.getId(), jwtUser.getUsername(), role, isRemember); + response.setHeader("token", JwtTokenUtil.TOKEN_PREFIX + token); + response.setCharacterEncoding("UTF-8"); + Map maps = new HashMap<>(MAP_INITIAL_CAPACITY); + maps.put("data", JwtTokenUtil.TOKEN_PREFIX + token); + maps.put("roles", role.split(SPLIT_COMMA)); + response.getWriter().write(JSONUtil.toJSONString(Results.success(maps))); + } finally { + rememberMe.remove(); + } + } + + @Override + protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException { + response.setCharacterEncoding("UTF-8"); + response.getWriter().write(JSONUtil.toJSONString(new ReturnT<>(ReturnT.JWT_FAIL_CODE, getMessage(failed)))); + } + + /** + * Return different echo information to the front end according to different exception types + */ + private String getMessage(AuthenticationException failed) { + String message = "Server Error"; + if (failed instanceof UsernameNotFoundException) { + message = "用户不存在"; + } else if (failed instanceof BadCredentialsException) { + message = "密码错误"; + } + return message; + } +} diff --git a/threadpool/server/auth/src/main/java/cn/hippo4j/auth/model/LdapUserInfo.java b/threadpool/server/auth/src/main/java/cn/hippo4j/auth/model/LdapUserInfo.java new file mode 100644 index 00000000..9a09c0b8 --- /dev/null +++ b/threadpool/server/auth/src/main/java/cn/hippo4j/auth/model/LdapUserInfo.java @@ -0,0 +1,39 @@ +package cn.hippo4j.auth.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Data; +import org.springframework.ldap.odm.annotations.Attribute; +import org.springframework.ldap.odm.annotations.DnAttribute; +import org.springframework.ldap.odm.annotations.Entry; +import org.springframework.ldap.odm.annotations.Id; + +import javax.naming.Name; + +@Data +@Entry(objectClasses = {"inetOrgPerson", "top"}) +public class LdapUserInfo { + + @JsonIgnore + @Id + private Name dn; + + @Attribute(name = "cn") + @DnAttribute(value = "cn") + private String userName; + + @Attribute(name = "sn") + private String lastName; + + @Attribute(name = "description") + private String description; + + @Attribute(name = "telephoneNumber") + private String telephoneNumber; + + @Attribute(name = "userPassword") + private String password; + + @Attribute(name = "ou") + private String organizational; + +} diff --git a/threadpool/server/auth/src/main/java/cn/hippo4j/auth/service/LdapService.java b/threadpool/server/auth/src/main/java/cn/hippo4j/auth/service/LdapService.java new file mode 100644 index 00000000..823286d3 --- /dev/null +++ b/threadpool/server/auth/src/main/java/cn/hippo4j/auth/service/LdapService.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.auth.service; + +/** + * Ldap service. + */ +public interface LdapService { + /** + * Login ldap + */ + void login(String username, String password); +} diff --git a/threadpool/server/auth/src/main/java/cn/hippo4j/auth/service/impl/LdapServiceImpl.java b/threadpool/server/auth/src/main/java/cn/hippo4j/auth/service/impl/LdapServiceImpl.java new file mode 100644 index 00000000..bb43be02 --- /dev/null +++ b/threadpool/server/auth/src/main/java/cn/hippo4j/auth/service/impl/LdapServiceImpl.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.auth.service.impl; + +import cn.hippo4j.auth.service.LdapService; +import cn.hippo4j.server.common.base.exception.ServiceException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.ldap.AuthenticationException; +import org.springframework.ldap.UncategorizedLdapException; +import org.springframework.ldap.core.LdapTemplate; +import org.springframework.ldap.query.LdapQueryBuilder; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import static org.springframework.ldap.query.LdapQueryBuilder.query; + +@Service +@Slf4j +public class LdapServiceImpl implements LdapService { + + private final LdapTemplate ldapTemplate; + + @Value("${spring.ldap.object-class:}") + private String objectClassName; + + @Value("${spring.ldap.account-attribute:}") + private String accountAttribute; + + public LdapServiceImpl(LdapTemplate ldapTemplate) { + this.ldapTemplate = ldapTemplate; + } + + @Override + public void login(String username, String password) { + try { + ldapTemplate.authenticate(LdapQueryBuilder.query() + .where(accountAttribute).is(username) + .and(query().where("objectClass").is(objectClassName)) + , password); + log.debug("{} ldap Login successful", username); + } catch (EmptyResultDataAccessException e) { + throw new UsernameNotFoundException("ldap Can't find the user information "); + } catch (AuthenticationException e) { + log.debug("The user name or account error"); + throw new BadCredentialsException("The username or password error"); + } catch (UncategorizedLdapException e) { + log.debug("Please check whether the user name password input"); + throw new BadCredentialsException("Please check whether the username password input"); + } catch (Exception e) { + throw new ServiceException("Abnormal server"); + } + } + +} diff --git a/threadpool/server/auth/src/main/java/cn/hippo4j/auth/service/impl/LdapUserDetailsServiceImpl.java b/threadpool/server/auth/src/main/java/cn/hippo4j/auth/service/impl/LdapUserDetailsServiceImpl.java new file mode 100644 index 00000000..ee5411f1 --- /dev/null +++ b/threadpool/server/auth/src/main/java/cn/hippo4j/auth/service/impl/LdapUserDetailsServiceImpl.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.auth.service.impl; + +import cn.hippo4j.auth.mapper.UserMapper; +import cn.hippo4j.auth.model.UserInfo; +import cn.hippo4j.auth.model.biz.user.JwtUser; +import cn.hippo4j.auth.model.biz.user.LoginUser; +import cn.hippo4j.auth.service.LdapService; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.Collections; +import java.util.Objects; +import java.util.Set; + +/** + * User details service impl. + */ +@Slf4j +@Service +public class LdapUserDetailsServiceImpl implements UserDetailsService { + + @Value("${hippo4j.core.auth.enabled:true}") + private Boolean enableAuthentication; + + @Resource + private UserMapper userMapper; + + @Resource + private LdapService ldapService; + + @Override + public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { + JwtUser anonymous = dealWithAnonymous(); + if (!Objects.isNull(anonymous)) { + return anonymous; + } + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(requestAttributes)).getRequest(); + LoginUser loginUser = (LoginUser) request.getAttribute("loginUser"); + // ldap authentication + ldapService.login(userName, loginUser.getPassword()); + // By querying the data inventory this user does not exist + UserInfo userInfo = userMapper.selectOne(Wrappers.lambdaQuery(UserInfo.class) + .eq(UserInfo::getUserName, userName) + ); + // the database does not, create a ROLE_USER permission to the default user, password is empty + if (Objects.isNull(userInfo)) { + userInfo = new UserInfo(); + userInfo.setPassword(""); + userInfo.setUserName(loginUser.getUsername()); + userInfo.setRole("ROLE_USER"); + userMapper.insert(userInfo); + } + // structure jwtUser + JwtUser jwtUser = new JwtUser(); + jwtUser.setId(userInfo.getId()); + jwtUser.setUsername(userName); + jwtUser.setPassword(""); + Set authorities = Collections.singleton(new SimpleGrantedAuthority(userInfo.getRole() + "")); + jwtUser.setAuthorities(authorities); + return jwtUser; + } + + private JwtUser dealWithAnonymous() { + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + if (requestAttributes == null) { + return null; + } + HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); + LoginUser loginUser = (LoginUser) request.getAttribute("loginUser"); + if (Objects.isNull(loginUser)) { + return null; + } + if (Boolean.FALSE.equals(enableAuthentication)) { + JwtUser jwtUser = new JwtUser(); + BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder(); + jwtUser.setId(1L); + jwtUser.setUsername("anonymous"); + jwtUser.setPassword(bCryptPasswordEncoder.encode(loginUser.getPassword())); + Set authorities = Collections.singleton(new SimpleGrantedAuthority("ROLE_ADMIN")); + jwtUser.setAuthorities(authorities); + return jwtUser; + } + return null; + } +} diff --git a/threadpool/server/auth/src/main/java/cn/hippo4j/auth/service/impl/UserDetailsServiceImpl.java b/threadpool/server/auth/src/main/java/cn/hippo4j/auth/service/impl/UserDetailsServiceImpl.java index dc62a170..960c25ab 100644 --- a/threadpool/server/auth/src/main/java/cn/hippo4j/auth/service/impl/UserDetailsServiceImpl.java +++ b/threadpool/server/auth/src/main/java/cn/hippo4j/auth/service/impl/UserDetailsServiceImpl.java @@ -24,11 +24,13 @@ import cn.hippo4j.auth.model.biz.user.LoginUser; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.stereotype.Service; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; @@ -43,6 +45,7 @@ import java.util.Set; * User details service impl. */ @Slf4j +@Service public class UserDetailsServiceImpl implements UserDetailsService { @Value("${hippo4j.core.auth.enabled:true}") @@ -57,10 +60,20 @@ public class UserDetailsServiceImpl implements UserDetailsService { if (!Objects.isNull(anonymous)) { return anonymous; } - UserInfo userInfo = userMapper.selectOne(Wrappers.lambdaQuery(UserInfo.class).eq(UserInfo::getUserName, userName)); + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + LoginUser loginUser = (LoginUser) request.getAttribute("loginUser"); + String loginPassword = loginUser.getPassword(); + UserInfo userInfo = userMapper.selectOne(Wrappers.lambdaQuery(UserInfo.class) + .eq(UserInfo::getUserName, userName) + ); if (Objects.isNull(userInfo)) { throw new UsernameNotFoundException(userName); } + // Validation password + BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder(); + if (!bCryptPasswordEncoder.matches(loginPassword, userInfo.getPassword())) { + throw new BadCredentialsException(userName + "密码错误,请重新输入"); + } JwtUser jwtUser = new JwtUser(); jwtUser.setId(userInfo.getId()); jwtUser.setUsername(userName); diff --git a/threadpool/server/auth/src/test/java/cn/hippo4j/auth/toolkit/BCryptPasswordEncoderTest.java b/threadpool/server/auth/src/test/java/cn/hippo4j/auth/toolkit/BCryptPasswordEncoderTest.java new file mode 100644 index 00000000..f1d8a24b --- /dev/null +++ b/threadpool/server/auth/src/test/java/cn/hippo4j/auth/toolkit/BCryptPasswordEncoderTest.java @@ -0,0 +1,20 @@ +package cn.hippo4j.auth.toolkit; + +import cn.hippo4j.common.toolkit.Assert; +import org.junit.Test; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +public class BCryptPasswordEncoderTest { + + @Test + public void bCryptPasswordEncoderTest() { + + String password = "12345abc"; + + BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder(); + String encode = bCryptPasswordEncoder.encode(password); + boolean matches = bCryptPasswordEncoder.matches(password, encode); + Assert.isTrue(matches); + } + +} diff --git a/threadpool/server/bootstrap/src/main/resources/ldap-back.properties b/threadpool/server/bootstrap/src/main/resources/ldap-back.properties new file mode 100644 index 00000000..5b950ede --- /dev/null +++ b/threadpool/server/bootstrap/src/main/resources/ldap-back.properties @@ -0,0 +1,14 @@ +#*************** Ldap Sample Configurations ***************# +### This configuration file does not take effect +### Change the LDAP server information to yourself +### Configure the following configuration file into application.properties + +# Ldap Config +spring.ldap.urls=ldap://127.0.0.1:389 +spring.ldap.base=dc=xxx,dc=com +spring.ldap.embedded.credential.username=cn=xxxx,dc=xxx,dc=com +spring.ldap.embedded.credential.password=password +# Ldap Entry object-class +spring.ldap.object-class=person +# Ldap account-attribute CommonName ( cn / uid / username / ... ) +spring.ldap.account-attribute=cn