mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2026-01-29 22:56:53 +08:00
Compare commits
27 Commits
springboot
...
v3.9.0last
| Author | SHA1 | Date | |
|---|---|---|---|
| 41877a6e8b | |||
| b7a3da89ca | |||
| de4a8ce652 | |||
| e533af285c | |||
| 23dc7b3f03 | |||
| e57aef0708 | |||
| 42087c0bf8 | |||
| 606edcc82f | |||
| 9082e986f1 | |||
| 40cd525bba | |||
| d6b6cf079e | |||
| 1b688e7cd2 | |||
| 58915a6410 | |||
| b67096dc54 | |||
| 67795493bd | |||
| e1c8f00bf2 | |||
| 17a81e89a5 | |||
| bcbf775756 | |||
| 462365890e | |||
| b686f9fbd1 | |||
| 872f84d006 | |||
| 26087172df | |||
| 281c3ff3c8 | |||
| 38d44c2487 | |||
| 8c88f8adf5 | |||
| adc191f03e | |||
| f6f2ef6316 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -13,6 +13,5 @@ os_del.cmd
|
|||||||
os_del_doc.cmd
|
os_del_doc.cmd
|
||||||
.svn
|
.svn
|
||||||
derby.log
|
derby.log
|
||||||
*.log
|
|
||||||
.cursor
|
.cursor
|
||||||
.history
|
.history
|
||||||
@ -3,9 +3,6 @@ AIGC应用平台介绍
|
|||||||
|
|
||||||
一个全栈式 AI 开发平台,旨在帮助开发者快速构建和部署个性化的 AI 应用。
|
一个全栈式 AI 开发平台,旨在帮助开发者快速构建和部署个性化的 AI 应用。
|
||||||
|
|
||||||
> JDK说明:AI流程编排引擎暂时不支持jdk21,所以目前只能使用jdk8或者jdk17启动项目。
|
|
||||||
|
|
||||||
|
|
||||||
JeecgBoot平台的AIGC功能模块,是一套类似`Dify`的`AIGC应用开发平台`+`知识库问答`,是一款基于LLM大语言模型AI应用平台和 RAG 的知识库问答系统。
|
JeecgBoot平台的AIGC功能模块,是一套类似`Dify`的`AIGC应用开发平台`+`知识库问答`,是一款基于LLM大语言模型AI应用平台和 RAG 的知识库问答系统。
|
||||||
其直观的界面结合了 AI 流程编排、RAG 管道、知识库管理、模型管理、对接向量库、实时运行可观察等,让您可以快速从原型到生产,拥有AI服务能力。
|
其直观的界面结合了 AI 流程编排、RAG 管道、知识库管理、模型管理、对接向量库、实时运行可观察等,让您可以快速从原型到生产,拥有AI服务能力。
|
||||||
|
|
||||||
@ -109,6 +106,10 @@ JeecgBoot平台的AIGC功能模块,是一套类似`Dify`的`AIGC应用开发
|
|||||||
| ChatGTP | √ |
|
| ChatGTP | √ |
|
||||||
| Qwq | √ |
|
| Qwq | √ |
|
||||||
| 智库 | √ |
|
| 智库 | √ |
|
||||||
|
| claude | √ |
|
||||||
|
| vl模型 | √ |
|
||||||
|
| 千帆大模型 | √ |
|
||||||
|
| 通义千问 | √ |
|
||||||
| Ollama本地搭建大模型 | √ |
|
| Ollama本地搭建大模型 | √ |
|
||||||
| 等等。。 | √ |
|
| 等等。。 | √ |
|
||||||
|
|
||||||
|
|||||||
@ -1,126 +0,0 @@
|
|||||||
|
|
||||||
JeecgBoot低代码平台(商业版介绍)
|
|
||||||
===============
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
项目介绍
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
<h3 align="center">企业级AI低代码平台</h3>
|
|
||||||
|
|
||||||
|
|
||||||
JeecgBoot是一款集成AI应用的,基于BPM流程的低代码平台,旨在帮助企业快速实现低代码开发和构建个性化AI应用,支持MCP和插件,实现聊天式业务操作(如 “一句话创建用户”)!
|
|
||||||
|
|
||||||
前后端分离架构Ant Design&Vue3,SpringBoot,SpringCloud Alibaba,Mybatis-plus,Shiro。强大的代码生成器让前后端代码一键生成,无需写任何代码! 引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE, 帮助Java项目解决80%的重复工作,让开发更多关注业务,提高效率、节省成本,同时又不失灵活性!低代码能力:Online表单、表单设计、流程设计、Online报表、大屏/仪表盘设计、报表设计; AI应用平台功能:AI知识库问答、AI模型管理、AI流程编排、AI聊天等,支持含ChatGPT、DeepSeek、Ollama等多种AI大模型
|
|
||||||
|
|
||||||
JeecgBoot 提供了一系列 `低代码能力`,实现`真正的零代码`在线开发:Online表单开发、Online报表、复杂报表设计、打印设计、在线图表设计、仪表盘设计、大屏设计、移动图表能力、表单设计器、在线设计流程、流程自动化配置、插件能力(可插拔)
|
|
||||||
|
|
||||||
`AI赋能低代码:` 目前提供了AI应用、AI模型管理、AI流程编排、AI对话助手,AI建表、AI写文章、AI知识库问答、AI字段建议等功能;支持各种AI大模型ChatGPT、DeepSeek、Ollama、智普、千问等.
|
|
||||||
|
|
||||||
`JEECG宗旨是:` 简单功能由OnlineCoding配置实现,做到`零代码开发`;复杂功能由代码生成器生成进行手工Merge 实现`低代码开发`,既保证了`智能`又兼顾`灵活`;实现了低代码开发的同时又支持灵活编码,解决了当前低代码产品普遍不灵活的弊端!
|
|
||||||
|
|
||||||
`JEECG业务流程:` 采用工作流来实现、扩展出任务接口,供开发编写业务逻辑,表单提供多种解决方案: 表单设计器、online配置表单、编码表单。同时实现了流程与表单的分离设计(松耦合)、并支持任务节点灵活配置,既保证了公司流程的保密性,又减少了开发人员的工作量。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### JeecgBoot商业版与同类产品区别
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
- 灵活性:jeecgboot基于开源技术栈,设计初考虑到可插拔性和集成灵活性,确保平台的智能性与灵活性,避免因平台过于庞大而导致的扩展困难。
|
|
||||||
- 流程管理:支持一个表单挂接多个流程,同时一个流程可以连接多个表单,增强了流程的灵活性和复杂性管理。
|
|
||||||
- 符合中国国情的流程:针对中国市场的特定需求,jeecgboot能够实现各种符合中国国情的业务流程。
|
|
||||||
- 强大的表单设计器:jeecgboot的表单设计器与敲敲云共享,具备高质量和智能化的特点,能够满足零代码应用的需求,业内同类产品中不多见。
|
|
||||||
- 报表功能:自主研发的报表工具,拥有独立知识产权,功能上比业内老牌产品如帆软更智能,操作简便。
|
|
||||||
- BI产品整合:提供大屏、仪表盘、门户等功能,完美解决这些需求,并支持移动面板的设计与渲染。
|
|
||||||
- 自主研发的模块:jeecgboot的所有模块均为自主研发,具有独立的知识产权。
|
|
||||||
- 颗粒度和功能细致:在功能细致度和颗粒度上,jeecgboot远超同类产品,尤其在零代码能力方面表现突出。
|
|
||||||
- 零代码应用管理:最新版支持与敲敲云的零代码应用管理能力的集成,使得jeecgboot既具备低代码,又具备零代码的应用能力,业内独一无二。
|
|
||||||
- 强大的代码生成器:作为开源代码生成器的先锋,jeecgboot在代码生成的智能化和在线低代码与代码生成的结合方面,优势明显。
|
|
||||||
- 精细化权限管理:提供行级和列级的数据权限控制,满足企业在ERP和OA领域对权限管理的严格需求。
|
|
||||||
- 多平台支持的APP:目前采用uniapp3实现,支持小程序、H5、App及鸿蒙、鸿蒙Next、Electron桌面应用等多种终端。
|
|
||||||
|
|
||||||
> 综上所述,jeecgboot不仅在功能上具备丰富性和灵活性,还在技术架构、权限管理和用户体验等方面展现出明显的优势,是一个综合性能强大的低代码平台。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
商业版演示
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
JeecgBoot vs 敲敲云
|
|
||||||
> - JeecgBoot是低代码产品拥有系列低代码能力,比如流程设计、表单设计、大屏设计,代码生成器,适合半开发模式(开发+低代码结合),也可以集成零代码应用管理模块.
|
|
||||||
> - 敲敲云是零代码产品,完全不写代码,通过配置搭建业务系统,其在jeecgboot基础上研发而成,删除了online、代码生成、OA等需要编码功能,只保留应用管理功能和聊天、日程、文件三个OA组件.
|
|
||||||
|
|
||||||
|
|
||||||
- JeecgBoot低代码: https://boot3.jeecg.com
|
|
||||||
- 敲敲云零代码:https://app.qiaoqiaoyun.com
|
|
||||||
- APP演示(多端): http://jeecg.com/appIndex
|
|
||||||
|
|
||||||
|
|
||||||
### 流程视频介绍
|
|
||||||
|
|
||||||
[](https://www.bilibili.com/video/BV1Nk4y1o7Qc)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 商业版功能简述
|
|
||||||
|
|
||||||
> 详细的功能介绍,[请联系官方](https://jeecg.com/vip)
|
|
||||||
|
|
||||||
```
|
|
||||||
│─更多商业功能
|
|
||||||
│ ├─流程设计器
|
|
||||||
│ ├─简流设计器(类钉钉版)
|
|
||||||
│ ├─门户设计(NEW)
|
|
||||||
│ ├─表单设计器
|
|
||||||
│ ├─大屏设计器
|
|
||||||
│ └─我的任务
|
|
||||||
│ └─历史流程
|
|
||||||
│ └─历史流程
|
|
||||||
│ └─流程实例管理
|
|
||||||
│ └─流程监听管理
|
|
||||||
│ └─流程表达式
|
|
||||||
│ └─我发起的流程
|
|
||||||
│ └─我的抄送
|
|
||||||
│ └─流程委派、抄送、跳转
|
|
||||||
│ └─OA办公组件
|
|
||||||
│ └─零代码应用管理(无需编码,在线搭建应用系统)
|
|
||||||
│ ├─积木报表企业版(含jimureport、jimubi)
|
|
||||||
│ ├─AI流程设计器源码
|
|
||||||
│ ├─Online全模块功能和源码
|
|
||||||
│ ├─AI写文章(CMS)
|
|
||||||
│ ├─AI表单字段建议(表单设计器)
|
|
||||||
│ ├─OA办公协同组件
|
|
||||||
│ ├─在线聊天功能
|
|
||||||
│ ├─设计表单移动适配
|
|
||||||
│ ├─设计表单支持外部填报
|
|
||||||
│ ├─设计表单AI字段建议
|
|
||||||
│ ├─设计表单视图功能(支持多种类型含日历、表格、看板、甘特图)
|
|
||||||
│ └─。。。
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##### 流程设计
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##### 表单设计器
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
|
[中文](./README.md) | English
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
15
README.md
15
README.md
@ -1,3 +1,4 @@
|
|||||||
|
中文 | [English](./README.en-US.md)
|
||||||
|
|
||||||
JeecgBoot AI低代码平台
|
JeecgBoot AI低代码平台
|
||||||
===============
|
===============
|
||||||
@ -232,20 +233,6 @@ JeecgBoot平台提供了一套完善的AI应用管理系统模块,是一套类
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
开源版与企业版区别?
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
- JeecgBoot开源版采用 [Apache-2.0 license](LICENSE) 协议附加补充条款:允许商用使用,不会造成侵权行为,允许基于本平台软件开展业务系统开发(但在任何情况下,您不得使用本软件开发可能被认为与本软件竞争的软件).
|
|
||||||
- 商业版与开源版主要区别在于商业版提供了技术支持 和 更多的企业级功能(例如:Online图表、流程监控、流程设计、流程审批、表单设计器、表单视图、积木报表企业版、OA办公、商业APP、零代码应用、Online模块源码等功能). [更多商业功能介绍,点击查看](README-Enterprise.md)
|
|
||||||
- JeecgBoot未来发展方向是:零代码平台的建设,也就是团队的另外一款产品 [敲敲云零代码](https://www.qiaoqiaoyun.com) ,无需编码即可通过拖拽快速搭建企业级应用,与JeecgBoot低代码平台形成互补,满足从简单业务到复杂系统的全场景开发需求,目前已经开源,[欢迎下载](https://qiaoqiaoyun.com/downloadCode)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Jeecg Boot 产品功能蓝图
|
### Jeecg Boot 产品功能蓝图
|
||||||

|

|
||||||
|
|
||||||
|
|||||||
1
jeecg-boot/.gitignore
vendored
1
jeecg-boot/.gitignore
vendored
@ -13,4 +13,3 @@ os_del.cmd
|
|||||||
os_del_doc.cmd
|
os_del_doc.cmd
|
||||||
.svn
|
.svn
|
||||||
derby.log
|
derby.log
|
||||||
*.log
|
|
||||||
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
JeecgBoot 低代码开发平台
|
JeecgBoot 低代码开发平台
|
||||||
===============
|
===============
|
||||||
|
|
||||||
|
|||||||
@ -1,45 +0,0 @@
|
|||||||
CREATE TABLE `oauth2_registered_client` (
|
|
||||||
`id` varchar(100) NOT NULL,
|
|
||||||
`client_id` varchar(100) NOT NULL,
|
|
||||||
`client_id_issued_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
`client_secret` varchar(200) DEFAULT NULL,
|
|
||||||
`client_secret_expires_at` timestamp NULL DEFAULT NULL,
|
|
||||||
`client_name` varchar(200) NOT NULL,
|
|
||||||
`client_authentication_methods` varchar(1000) NOT NULL,
|
|
||||||
`authorization_grant_types` varchar(1000) NOT NULL,
|
|
||||||
`redirect_uris` varchar(1000) DEFAULT NULL,
|
|
||||||
`post_logout_redirect_uris` varchar(1000) DEFAULT NULL,
|
|
||||||
`scopes` varchar(1000) NOT NULL,
|
|
||||||
`client_settings` varchar(2000) NOT NULL,
|
|
||||||
`token_settings` varchar(2000) NOT NULL,
|
|
||||||
PRIMARY KEY (`id`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
|
||||||
|
|
||||||
INSERT INTO `oauth2_registered_client`
|
|
||||||
(`id`,
|
|
||||||
`client_id`,
|
|
||||||
`client_id_issued_at`,
|
|
||||||
`client_secret`,
|
|
||||||
`client_secret_expires_at`,
|
|
||||||
`client_name`,
|
|
||||||
`client_authentication_methods`,
|
|
||||||
`authorization_grant_types`,
|
|
||||||
`redirect_uris`,
|
|
||||||
`post_logout_redirect_uris`,
|
|
||||||
`scopes`,
|
|
||||||
`client_settings`,
|
|
||||||
`token_settings`)
|
|
||||||
VALUES
|
|
||||||
('3eacac0e-0de9-4727-9a64-6bdd4be2ee1f',
|
|
||||||
'jeecg-client',
|
|
||||||
now(),
|
|
||||||
'secret',
|
|
||||||
null,
|
|
||||||
'3eacac0e-0de9-4727-9a64-6bdd4be2ee1f',
|
|
||||||
'client_secret_basic',
|
|
||||||
'refresh_token,authorization_code,password,app,phone,social',
|
|
||||||
'http://127.0.0.1:8080/jeecg-',
|
|
||||||
'http://127.0.0.1:8080/',
|
|
||||||
'*',
|
|
||||||
'{"@class":"java.util.Collections$UnmodifiableMap","settings.client.require-proof-key":false,"settings.client.require-authorization-consent":true}',
|
|
||||||
'{"@class":"java.util.Collections$UnmodifiableMap","settings.token.reuse-refresh-tokens":true,"settings.token.id-token-signature-algorithm":["org.springframework.security.oauth2.jose.jws.SignatureAlgorithm","RS256"],"settings.token.access-token-time-to-live":["java.time.Duration",300000.000000000],"settings.token.access-token-format":{"@class":"org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat","value":"self-contained"},"settings.token.refresh-token-time-to-live":["java.time.Duration",3600.000000000],"settings.token.authorization-code-time-to-live":["java.time.Duration",300000.000000000],"settings.token.device-code-time-to-live":["java.time.Duration",300000.000000000]}');
|
|
||||||
@ -192,19 +192,76 @@
|
|||||||
<version>${java-jwt.version}</version>
|
<version>${java-jwt.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!--shiro-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.apache.shiro</groupId>
|
||||||
<artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
|
<artifactId>shiro-spring-boot-starter</artifactId>
|
||||||
|
<classifier>jakarta</classifier>
|
||||||
|
<version>${shiro.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.shiro</groupId>
|
||||||
|
<artifactId>shiro-spring</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.apache.shiro</groupId>
|
||||||
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
|
<artifactId>shiro-spring</artifactId>
|
||||||
|
<classifier>jakarta</classifier>
|
||||||
|
<version>${shiro.version}</version>
|
||||||
|
<!-- 排除仍使用了javax.servlet的依赖 -->
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.shiro</groupId>
|
||||||
|
<artifactId>shiro-core</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.shiro</groupId>
|
||||||
|
<artifactId>shiro-web</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- 添加spring security cas支持 -->
|
<!-- 引入适配jakarta的依赖包 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.apache.shiro</groupId>
|
||||||
<artifactId>spring-security-cas</artifactId>
|
<artifactId>shiro-core</artifactId>
|
||||||
|
<classifier>jakarta</classifier>
|
||||||
|
<version>${shiro.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>commons-beanutils</groupId>
|
||||||
|
<artifactId>commons-beanutils</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.shiro</groupId>
|
||||||
|
<artifactId>shiro-web</artifactId>
|
||||||
|
<classifier>jakarta</classifier>
|
||||||
|
<version>${shiro.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.shiro</groupId>
|
||||||
|
<artifactId>shiro-core</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<!-- shiro-redis -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.crazycake</groupId>
|
||||||
|
<artifactId>shiro-redis</artifactId>
|
||||||
|
<version>${shiro-redis.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.shiro</groupId>
|
||||||
|
<artifactId>shiro-core</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>checkstyle</artifactId>
|
||||||
|
<groupId>com.puppycrawl.tools</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@ -1,21 +0,0 @@
|
|||||||
package org.apache.shiro;
|
|
||||||
|
|
||||||
import org.apache.shiro.subject.Subject;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 兼容处理Online功能使用处理,请勿修改
|
|
||||||
* @author eightmonth@qq.com
|
|
||||||
* @date 2024/4/29 14:05
|
|
||||||
*/
|
|
||||||
public class SecurityUtils {
|
|
||||||
|
|
||||||
|
|
||||||
public static Subject getSubject() {
|
|
||||||
return new Subject() {
|
|
||||||
@Override
|
|
||||||
public Object getPrincipal() {
|
|
||||||
return Subject.super.getPrincipal();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
package org.apache.shiro.subject;
|
|
||||||
|
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 兼容处理Online功能使用处理,请勿修改
|
|
||||||
* @author eightmonth@qq.com
|
|
||||||
* @date 2024/4/29 14:18
|
|
||||||
*/
|
|
||||||
public interface Subject {
|
|
||||||
default Object getPrincipal() {
|
|
||||||
return SecureUtil.currentUser();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,6 +1,5 @@
|
|||||||
package org.jeecg.common.api;
|
package org.jeecg.common.api;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import org.jeecg.common.api.dto.AiragFlowDTO;
|
import org.jeecg.common.api.dto.AiragFlowDTO;
|
||||||
import org.jeecg.common.system.vo.*;
|
import org.jeecg.common.system.vo.*;
|
||||||
|
|
||||||
@ -66,13 +65,6 @@ public interface CommonAPI {
|
|||||||
*/
|
*/
|
||||||
public String getUserIdByName(String username);
|
public String getUserIdByName(String username);
|
||||||
|
|
||||||
/**
|
|
||||||
* 5根据用户手机号查询用户信息
|
|
||||||
* @param username
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public LoginUser getUserByPhone(String phone);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 6字典表的 翻译
|
* 6字典表的 翻译
|
||||||
@ -162,31 +154,4 @@ public interface CommonAPI {
|
|||||||
*/
|
*/
|
||||||
Object runAiragFlow(AiragFlowDTO airagFlowDTO);
|
Object runAiragFlow(AiragFlowDTO airagFlowDTO);
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录加载系统字典
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
Map<String,List<DictModel>> queryAllDictItems();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询SysDepart集合
|
|
||||||
* @param userId
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
List<SysDepartModel> queryUserDeparts(String userId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据用户名设置部门ID
|
|
||||||
* @param username
|
|
||||||
* @param orgCode
|
|
||||||
*/
|
|
||||||
void updateUserDepart(String username,String orgCode,Integer loginTenantId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置登录租户
|
|
||||||
* @param username
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
JSONObject setLoginTenant(String username);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
package org.jeecg.common.aspect;
|
package org.jeecg.common.aspect;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.alibaba.fastjson.serializer.PropertyFilter;
|
import com.alibaba.fastjson.serializer.PropertyFilter;
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
@ -16,14 +15,12 @@ import org.jeecg.common.aspect.annotation.AutoLog;
|
|||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.constant.enums.ModuleType;
|
import org.jeecg.common.constant.enums.ModuleType;
|
||||||
import org.jeecg.common.constant.enums.OperateTypeEnum;
|
import org.jeecg.common.constant.enums.OperateTypeEnum;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecg.modules.base.service.BaseCommonService;
|
import org.jeecg.modules.base.service.BaseCommonService;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import org.jeecg.common.util.IpUtils;
|
import org.jeecg.common.util.IpUtils;
|
||||||
import org.jeecg.common.util.SpringContextUtils;
|
import org.jeecg.common.util.SpringContextUtils;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.springframework.core.StandardReflectionParameterNameDiscoverer;
|
import org.springframework.core.StandardReflectionParameterNameDiscoverer;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
@ -103,7 +100,7 @@ public class AutoLogAspect {
|
|||||||
//设置IP地址
|
//设置IP地址
|
||||||
dto.setIp(IpUtils.getIpAddr(request));
|
dto.setIp(IpUtils.getIpAddr(request));
|
||||||
//获取登录用户信息
|
//获取登录用户信息
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
if(sysUser!=null){
|
if(sysUser!=null){
|
||||||
dto.setUserid(sysUser.getUsername());
|
dto.setUserid(sysUser.getUsername());
|
||||||
dto.setUsername(sysUser.getRealname());
|
dto.setUsername(sysUser.getRealname());
|
||||||
|
|||||||
@ -90,9 +90,9 @@ public interface CommonConstant {
|
|||||||
/** 登录用户Shiro权限缓存KEY前缀 */
|
/** 登录用户Shiro权限缓存KEY前缀 */
|
||||||
public static String PREFIX_USER_SHIRO_CACHE = "shiro:cache:org.jeecg.config.shiro.ShiroRealm.authorizationCache:";
|
public static String PREFIX_USER_SHIRO_CACHE = "shiro:cache:org.jeecg.config.shiro.ShiroRealm.authorizationCache:";
|
||||||
/** 登录用户Token令牌缓存KEY前缀 */
|
/** 登录用户Token令牌缓存KEY前缀 */
|
||||||
String PREFIX_USER_TOKEN = "token::jeecg-client::";
|
String PREFIX_USER_TOKEN = "prefix_user_token:";
|
||||||
/** 登录用户Token令牌作废提示信息,比如 “不允许同一账号多地同时登录,会往这个变量存提示信息” */
|
/** 登录用户Token令牌作废提示信息,比如 “不允许同一账号多地同时登录,会往这个变量存提示信息” */
|
||||||
String PREFIX_USER_TOKEN_ERROR_MSG = "token::jeecg-client::error:msg_";
|
String PREFIX_USER_TOKEN_ERROR_MSG = "prefix_user_token:error:msg_";
|
||||||
|
|
||||||
/**============================== 【是否允许同一账号多地同时登录】登录客户端类型常量 ==============================*/
|
/**============================== 【是否允许同一账号多地同时登录】登录客户端类型常量 ==============================*/
|
||||||
/** 客户端类型:PC端 */
|
/** 客户端类型:PC端 */
|
||||||
@ -101,11 +101,11 @@ public interface CommonConstant {
|
|||||||
String CLIENT_TYPE_APP = "APP";
|
String CLIENT_TYPE_APP = "APP";
|
||||||
/** 客户端类型:手机号登录 */
|
/** 客户端类型:手机号登录 */
|
||||||
String CLIENT_TYPE_PHONE = "PHONE";
|
String CLIENT_TYPE_PHONE = "PHONE";
|
||||||
String PREFIX_USER_TOKEN_PC = "token::jeecg-client::single_login:pc:";
|
String PREFIX_USER_TOKEN_PC = "prefix_user_token:single_login:pc:";
|
||||||
/** 单点登录:用户在APP端的Token缓存KEY前缀 (username -> token) */
|
/** 单点登录:用户在APP端的Token缓存KEY前缀 (username -> token) */
|
||||||
String PREFIX_USER_TOKEN_APP = "token::jeecg-client::single_login:app:";
|
String PREFIX_USER_TOKEN_APP = "prefix_user_token:single_login:app:";
|
||||||
/** 单点登录:用户在手机号登录的Token缓存KEY前缀 (username -> token) */
|
/** 单点登录:用户在手机号登录的Token缓存KEY前缀 (username -> token) */
|
||||||
String PREFIX_USER_TOKEN_PHONE = "token::jeecg-client::single_login:phone:";
|
String PREFIX_USER_TOKEN_PHONE = "prefix_user_token:single_login:phone:";
|
||||||
/**============================== 【是否允许同一账号多地同时登录】登录客户端类型常量 ==============================*/
|
/**============================== 【是否允许同一账号多地同时登录】登录客户端类型常量 ==============================*/
|
||||||
|
|
||||||
// /** Token缓存时间:3600秒即一小时 */
|
// /** Token缓存时间:3600秒即一小时 */
|
||||||
|
|||||||
@ -6,6 +6,8 @@ import jakarta.servlet.http.HttpServletRequest;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.authz.AuthorizationException;
|
||||||
|
import org.apache.shiro.authz.UnauthorizedException;
|
||||||
import org.jeecg.common.api.dto.LogDTO;
|
import org.jeecg.common.api.dto.LogDTO;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
@ -22,8 +24,6 @@ import org.springframework.dao.DataIntegrityViolationException;
|
|||||||
import org.springframework.dao.DuplicateKeyException;
|
import org.springframework.dao.DuplicateKeyException;
|
||||||
import org.springframework.data.redis.connection.PoolException;
|
import org.springframework.data.redis.connection.PoolException;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.validation.ObjectError;
|
import org.springframework.validation.ObjectError;
|
||||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||||
@ -47,27 +47,9 @@ import java.util.stream.Collectors;
|
|||||||
@RestControllerAdvice
|
@RestControllerAdvice
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class JeecgBootExceptionHandler {
|
public class JeecgBootExceptionHandler {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
BaseCommonService baseCommonService;
|
BaseCommonService baseCommonService;
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证码错误异常
|
|
||||||
*/
|
|
||||||
|
|
||||||
@ExceptionHandler(JeecgCaptchaException.class)
|
|
||||||
@ResponseStatus(HttpStatus.OK)
|
|
||||||
public Result<?> handleJeecgCaptchaException(JeecgCaptchaException e) {
|
|
||||||
log.error(e.getMessage(), e);
|
|
||||||
return Result.error(e.getCode(), e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
@ExceptionHandler(AuthenticationException.class)
|
|
||||||
@ResponseStatus(HttpStatus.OK)
|
|
||||||
public Result<?> handleJeecgCaptchaException(AuthenticationException e) {
|
|
||||||
log.error(e.getMessage(), e);
|
|
||||||
return Result.error(401, e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||||
public Result<?> handleValidationExceptions(MethodArgumentNotValidException e) {
|
public Result<?> handleValidationExceptions(MethodArgumentNotValidException e) {
|
||||||
@ -130,8 +112,8 @@ public class JeecgBootExceptionHandler {
|
|||||||
return Result.error("数据库中已存在该记录");
|
return Result.error("数据库中已存在该记录");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(AccessDeniedException.class)
|
@ExceptionHandler({UnauthorizedException.class, AuthorizationException.class})
|
||||||
public Result<?> handleAuthorizationException(AccessDeniedException e){
|
public Result<?> handleAuthorizationException(AuthorizationException e){
|
||||||
log.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
return Result.noauth("没有权限,请联系管理员分配权限!");
|
return Result.noauth("没有权限,请联系管理员分配权限!");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,28 +0,0 @@
|
|||||||
package org.jeecg.common.exception;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author kezhijie@wuhandsj.com
|
|
||||||
* @date 2024/1/2 11:38
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class JeecgCaptchaException extends RuntimeException{
|
|
||||||
|
|
||||||
private Integer code;
|
|
||||||
|
|
||||||
private static final long serialVersionUID = -9093410345065209053L;
|
|
||||||
|
|
||||||
public JeecgCaptchaException(Integer code, String message) {
|
|
||||||
super(message);
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JeecgCaptchaException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public JeecgCaptchaException(Throwable cause) {
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,6 +1,5 @@
|
|||||||
package org.jeecg.common.system.base.controller;
|
package org.jeecg.common.system.base.controller;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
@ -13,7 +12,6 @@ import org.jeecg.common.system.query.QueryGenerator;
|
|||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.config.JeecgBaseConfig;
|
import org.jeecg.config.JeecgBaseConfig;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
||||||
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
|
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
|
||||||
import org.jeecgframework.poi.excel.entity.ExportParams;
|
import org.jeecgframework.poi.excel.entity.ExportParams;
|
||||||
@ -22,7 +20,6 @@ import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
|
|||||||
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
|
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
|
||||||
import org.jeecgframework.poi.handler.inter.IExcelExportServer;
|
import org.jeecgframework.poi.handler.inter.IExcelExportServer;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
@ -55,7 +52,7 @@ public class JeecgController<T, S extends IService<T>> {
|
|||||||
protected ModelAndView exportXls(HttpServletRequest request, T object, Class<T> clazz, String title) {
|
protected ModelAndView exportXls(HttpServletRequest request, T object, Class<T> clazz, String title) {
|
||||||
// Step.1 组装查询条件
|
// Step.1 组装查询条件
|
||||||
QueryWrapper<T> queryWrapper = QueryGenerator.initQueryWrapper(object, request.getParameterMap());
|
QueryWrapper<T> queryWrapper = QueryGenerator.initQueryWrapper(object, request.getParameterMap());
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
|
|
||||||
// 过滤选中数据
|
// 过滤选中数据
|
||||||
String selections = request.getParameter("selections");
|
String selections = request.getParameter("selections");
|
||||||
@ -97,7 +94,7 @@ public class JeecgController<T, S extends IService<T>> {
|
|||||||
protected ModelAndView exportXlsSheet(HttpServletRequest request, T object, Class<T> clazz, String title,String exportFields,Integer pageNum) {
|
protected ModelAndView exportXlsSheet(HttpServletRequest request, T object, Class<T> clazz, String title,String exportFields,Integer pageNum) {
|
||||||
// Step.1 组装查询条件
|
// Step.1 组装查询条件
|
||||||
QueryWrapper<T> queryWrapper = QueryGenerator.initQueryWrapper(object, request.getParameterMap());
|
QueryWrapper<T> queryWrapper = QueryGenerator.initQueryWrapper(object, request.getParameterMap());
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
// Step.2 计算分页sheet数据
|
// Step.2 计算分页sheet数据
|
||||||
double total = service.count();
|
double total = service.count();
|
||||||
int count = (int)Math.ceil(total/pageNum);
|
int count = (int)Math.ceil(total/pageNum);
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
package org.jeecg.common.system.util;
|
package org.jeecg.common.system.util;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
|
||||||
import com.auth0.jwt.JWT;
|
import com.auth0.jwt.JWT;
|
||||||
import com.auth0.jwt.JWTVerifier;
|
import com.auth0.jwt.JWTVerifier;
|
||||||
import com.auth0.jwt.algorithms.Algorithm;
|
import com.auth0.jwt.algorithms.Algorithm;
|
||||||
@ -12,9 +10,9 @@ import com.google.common.base.Joiner;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.*;
|
import java.util.Date;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import jakarta.servlet.ServletResponse;
|
import jakarta.servlet.ServletResponse;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
@ -22,7 +20,7 @@ import jakarta.servlet.http.HttpServletResponse;
|
|||||||
import jakarta.servlet.http.HttpSession;
|
import jakarta.servlet.http.HttpSession;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jeecg.common.api.CommonAPI;
|
import org.apache.shiro.SecurityUtils;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.constant.DataBaseConstant;
|
import org.jeecg.common.constant.DataBaseConstant;
|
||||||
@ -34,22 +32,6 @@ import org.jeecg.common.system.vo.SysUserCacheInfo;
|
|||||||
import org.jeecg.common.util.DateUtils;
|
import org.jeecg.common.util.DateUtils;
|
||||||
import org.jeecg.common.util.SpringContextUtils;
|
import org.jeecg.common.util.SpringContextUtils;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.config.security.self.SelfAuthenticationProvider;
|
|
||||||
import org.jeecg.config.security.self.SelfAuthenticationToken;
|
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.security.oauth2.core.*;
|
|
||||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.context.AuthorizationServerContextHolder;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author Scott
|
* @Author Scott
|
||||||
@ -65,33 +47,30 @@ public class JwtUtil {
|
|||||||
public static final long APP_EXPIRE_TIME = (30 * 12) * 60 * 60 * 1000L;
|
public static final long APP_EXPIRE_TIME = (30 * 12) * 60 * 60 * 1000L;
|
||||||
static final String WELL_NUMBER = SymbolConstant.WELL_NUMBER + SymbolConstant.LEFT_CURLY_BRACKET;
|
static final String WELL_NUMBER = SymbolConstant.WELL_NUMBER + SymbolConstant.LEFT_CURLY_BRACKET;
|
||||||
|
|
||||||
public static final String DEFAULT_CLIENT = "jeecg-client";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param response
|
* @param response
|
||||||
* @param code
|
* @param code
|
||||||
* @param errorMsg
|
* @param errorMsg
|
||||||
*/
|
*/
|
||||||
public static void responseError(ServletResponse response, Integer code, String errorMsg) {
|
public static void responseError(HttpServletResponse response, Integer code, String errorMsg) {
|
||||||
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
|
try {
|
||||||
// issues/I4YH95浏览器显示乱码问题
|
Result jsonResult = new Result(code, errorMsg);
|
||||||
httpServletResponse.setHeader("Content-type", "text/html;charset=UTF-8");
|
jsonResult.setSuccess(false);
|
||||||
response.setContentType("application/json;charset=UTF-8");
|
|
||||||
Result jsonResult = new Result(code, errorMsg);
|
// 设置响应头和内容类型
|
||||||
jsonResult.setSuccess(false);
|
response.setStatus(code);
|
||||||
OutputStream os = null;
|
response.setHeader("Content-type", "text/html;charset=UTF-8");
|
||||||
try {
|
response.setContentType("application/json;charset=UTF-8");
|
||||||
os = httpServletResponse.getOutputStream();
|
// 使用 ObjectMapper 序列化为 JSON 字符串
|
||||||
httpServletResponse.setCharacterEncoding("UTF-8");
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
httpServletResponse.setStatus(code);
|
String json = objectMapper.writeValueAsString(jsonResult);
|
||||||
os.write(new ObjectMapper().writeValueAsString(jsonResult).getBytes("UTF-8"));
|
response.getWriter().write(json);
|
||||||
os.flush();
|
response.getWriter().flush();
|
||||||
os.close();
|
} catch (IOException e) {
|
||||||
} catch (IOException e) {
|
|
||||||
log.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验token是否正确
|
* 校验token是否正确
|
||||||
@ -103,9 +82,10 @@ public class JwtUtil {
|
|||||||
public static boolean verify(String token, String username, String secret) {
|
public static boolean verify(String token, String username, String secret) {
|
||||||
try {
|
try {
|
||||||
// 根据密码生成JWT效验器
|
// 根据密码生成JWT效验器
|
||||||
JwtDecoder jwtDecoder = SpringContextUtils.getBean(JwtDecoder.class);
|
Algorithm algorithm = Algorithm.HMAC256(secret);
|
||||||
|
JWTVerifier verifier = JWT.require(algorithm).withClaim("username", username).build();
|
||||||
// 效验TOKEN
|
// 效验TOKEN
|
||||||
jwtDecoder.decode(token);
|
DecodedJWT jwt = verifier.verify(token);
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Token验证失败:" + e.getMessage(),e);
|
log.warn("Token验证失败:" + e.getMessage(),e);
|
||||||
@ -129,7 +109,7 @@ public class JwtUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成token
|
* 生成签名,5min后过期
|
||||||
*
|
*
|
||||||
* @param username 用户名
|
* @param username 用户名
|
||||||
* @param secret 用户的密码
|
* @param secret 用户的密码
|
||||||
@ -138,18 +118,29 @@ public class JwtUtil {
|
|||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static String sign(String username, String secret) {
|
public static String sign(String username, String secret) {
|
||||||
Map<String, Object> additionalParameter = new HashMap<>();
|
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
|
||||||
additionalParameter.put("username", username);
|
Algorithm algorithm = Algorithm.HMAC256(secret);
|
||||||
|
// 附带username信息
|
||||||
|
return JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm);
|
||||||
|
|
||||||
RegisteredClientRepository registeredClientRepository = SpringContextUtils.getBean(RegisteredClientRepository.class);
|
}
|
||||||
SelfAuthenticationProvider selfAuthenticationProvider = SpringContextUtils.getBean(SelfAuthenticationProvider.class);
|
|
||||||
|
|
||||||
OAuth2ClientAuthenticationToken client = new OAuth2ClientAuthenticationToken(Objects.requireNonNull(registeredClientRepository.findByClientId("jeecg-client")), ClientAuthenticationMethod.CLIENT_SECRET_BASIC, null);
|
|
||||||
client.setAuthenticated(true);
|
/**
|
||||||
SelfAuthenticationToken selfAuthenticationToken = new SelfAuthenticationToken(client, additionalParameter);
|
* 生成签名,5min后过期
|
||||||
selfAuthenticationToken.setAuthenticated(true);
|
*
|
||||||
OAuth2AccessTokenAuthenticationToken accessToken = (OAuth2AccessTokenAuthenticationToken) selfAuthenticationProvider.authenticate(selfAuthenticationToken);
|
* @param username 用户名
|
||||||
return accessToken.getAccessToken().getTokenValue();
|
* @param secret 用户的密码
|
||||||
|
* @param expireTime 过期时间
|
||||||
|
* @return 加密的token
|
||||||
|
* @deprecated 请使用sign(String username, String secret, String clientType)方法代替
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static String sign(String username, String secret, Long expireTime) {
|
||||||
|
Date date = new Date(System.currentTimeMillis() + expireTime);
|
||||||
|
Algorithm algorithm = Algorithm.HMAC256(secret);
|
||||||
|
// 附带username信息
|
||||||
|
return JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,36 +154,20 @@ public class JwtUtil {
|
|||||||
* @return 加密的token
|
* @return 加密的token
|
||||||
*/
|
*/
|
||||||
public static String sign(String username, String secret, String clientType) {
|
public static String sign(String username, String secret, String clientType) {
|
||||||
Map<String, Object> additionalParameter = new HashMap<>();
|
|
||||||
additionalParameter.put("username", username);
|
|
||||||
additionalParameter.put("clientType", clientType);
|
|
||||||
|
|
||||||
// 根据客户端类型选择对应的过期时间
|
// 根据客户端类型选择对应的过期时间
|
||||||
long expireTime = CommonConstant.CLIENT_TYPE_APP.equalsIgnoreCase(clientType)
|
long expireTime = CommonConstant.CLIENT_TYPE_APP.equalsIgnoreCase(clientType)
|
||||||
? APP_EXPIRE_TIME
|
? APP_EXPIRE_TIME
|
||||||
: EXPIRE_TIME;
|
: EXPIRE_TIME;
|
||||||
additionalParameter.put("expireTime", expireTime);
|
Date date = new Date(System.currentTimeMillis() + expireTime);
|
||||||
|
Algorithm algorithm = Algorithm.HMAC256(secret);
|
||||||
RegisteredClientRepository registeredClientRepository = SpringContextUtils.getBean(RegisteredClientRepository.class);
|
// 附带username和clientType信息
|
||||||
SelfAuthenticationProvider selfAuthenticationProvider = SpringContextUtils.getBean(SelfAuthenticationProvider.class);
|
return JWT.create()
|
||||||
|
.withClaim("username", username)
|
||||||
OAuth2ClientAuthenticationToken client = new OAuth2ClientAuthenticationToken(
|
.withClaim("clientType", clientType)
|
||||||
Objects.requireNonNull(registeredClientRepository.findByClientId(DEFAULT_CLIENT)),
|
.withExpiresAt(date)
|
||||||
ClientAuthenticationMethod.CLIENT_SECRET_BASIC,
|
.sign(algorithm);
|
||||||
null
|
|
||||||
);
|
|
||||||
client.setAuthenticated(true);
|
|
||||||
|
|
||||||
SelfAuthenticationToken selfAuthenticationToken = new SelfAuthenticationToken(client, additionalParameter);
|
|
||||||
selfAuthenticationToken.setAuthenticated(true);
|
|
||||||
|
|
||||||
OAuth2AccessTokenAuthenticationToken accessToken =
|
|
||||||
(OAuth2AccessTokenAuthenticationToken) selfAuthenticationProvider.authenticate(selfAuthenticationToken);
|
|
||||||
|
|
||||||
return accessToken.getAccessToken().getTokenValue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从token中获取客户端类型
|
* 从token中获取客户端类型
|
||||||
* for [JHHB-1030]【鉴权】移动端用户token到期后续期时间变成pc端时长
|
* for [JHHB-1030]【鉴权】移动端用户token到期后续期时间变成pc端时长
|
||||||
@ -273,7 +248,7 @@ public class JwtUtil {
|
|||||||
//2.通过shiro获取登录用户信息
|
//2.通过shiro获取登录用户信息
|
||||||
LoginUser sysUser = null;
|
LoginUser sysUser = null;
|
||||||
try {
|
try {
|
||||||
sysUser = SecureUtil.currentUser();
|
sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("SecurityUtils.getSubject() 获取用户信息异常:" + e.getMessage());
|
log.warn("SecurityUtils.getSubject() 获取用户信息异常:" + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,9 +3,7 @@ package org.jeecg.common.system.util;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jeecg.common.system.annotation.EnumDict;
|
import org.jeecg.common.system.annotation.EnumDict;
|
||||||
import org.jeecg.common.system.vo.DictModel;
|
import org.jeecg.common.system.vo.DictModel;
|
||||||
import org.jeecg.common.util.SpringContextUtils;
|
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||||
@ -13,6 +11,7 @@ import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
|||||||
import org.springframework.core.type.classreading.MetadataReader;
|
import org.springframework.core.type.classreading.MetadataReader;
|
||||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@ -183,10 +182,10 @@ public class ResourceUtil {
|
|||||||
for (DictModel dm : dictItemList) {
|
for (DictModel dm : dictItemList) {
|
||||||
String value = dm.getValue();
|
String value = dm.getValue();
|
||||||
if (keySet.contains(value)) {
|
if (keySet.contains(value)) {
|
||||||
List<DictModel> list = new ArrayList<>();
|
// 修复bug:获取或创建该dictCode对应的list,而不是每次都创建新的list
|
||||||
|
List<DictModel> list = map.computeIfAbsent(code, k -> new ArrayList<>());
|
||||||
list.add(new DictModel(value, dm.getText()));
|
list.add(new DictModel(value, dm.getText()));
|
||||||
map.put(code, list);
|
//break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,18 +1,13 @@
|
|||||||
package org.jeecg.common.system.vo;
|
package org.jeecg.common.system.vo;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
import org.jeecg.common.desensitization.annotation.SensitiveField;
|
import org.jeecg.common.desensitization.annotation.SensitiveField;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@ -25,10 +20,8 @@ import java.util.Set;
|
|||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class LoginUser implements Serializable {
|
public class LoginUser {
|
||||||
|
|
||||||
|
|
||||||
private static final long serialVersionUID = -7143159031677245866L;
|
|
||||||
/**
|
/**
|
||||||
* 登录人id
|
* 登录人id
|
||||||
*/
|
*/
|
||||||
@ -155,30 +148,4 @@ public class LoginUser implements Serializable {
|
|||||||
* 主岗位
|
* 主岗位
|
||||||
*/
|
*/
|
||||||
private String mainDepPostId;
|
private String mainDepPostId;
|
||||||
|
|
||||||
@SensitiveField
|
|
||||||
private String salt;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
// 重新构建对象过滤一些敏感字段
|
|
||||||
LoginUser loginUser = new LoginUser();
|
|
||||||
loginUser.setId(id);
|
|
||||||
loginUser.setUsername(username);
|
|
||||||
loginUser.setRealname(realname);
|
|
||||||
loginUser.setOrgCode(orgCode);
|
|
||||||
loginUser.setSex(sex);
|
|
||||||
loginUser.setEmail(email);
|
|
||||||
loginUser.setPhone(phone);
|
|
||||||
loginUser.setDelFlag(delFlag);
|
|
||||||
loginUser.setStatus(status);
|
|
||||||
loginUser.setActivitiSync(activitiSync);
|
|
||||||
loginUser.setUserIdentity(userIdentity);
|
|
||||||
loginUser.setDepartIds(departIds);
|
|
||||||
loginUser.setPost(post);
|
|
||||||
loginUser.setTelephone(telephone);
|
|
||||||
loginUser.setRelTenantIds(relTenantIds);
|
|
||||||
loginUser.setClientId(clientId);
|
|
||||||
return JSON.toJSONString(loginUser);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,17 @@
|
|||||||
package org.jeecg.common.util;
|
package org.jeecg.common.util;
|
||||||
|
|
||||||
import org.springframework.security.core.context.SecurityContext;
|
import org.apache.shiro.SecurityUtils;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.apache.shiro.mgt.SecurityManager;
|
||||||
|
import org.apache.shiro.subject.Subject;
|
||||||
|
import org.apache.shiro.util.ThreadContext;
|
||||||
|
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @date 2025-09-04
|
* @date 2025-09-04
|
||||||
* @author scott
|
* @author scott
|
||||||
*
|
*
|
||||||
* @Description: 支持Spring Security的API,获取当前登录人方法的线程池
|
* @Description: 支持shiro的API,获取当前登录人方法的线程池
|
||||||
*/
|
*/
|
||||||
public class ShiroThreadPoolExecutor extends ThreadPoolExecutor {
|
public class ShiroThreadPoolExecutor extends ThreadPoolExecutor {
|
||||||
|
|
||||||
@ -18,14 +21,16 @@ public class ShiroThreadPoolExecutor extends ThreadPoolExecutor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(Runnable command) {
|
public void execute(Runnable command) {
|
||||||
SecurityContext context = SecurityContextHolder.getContext();
|
Subject subject = SecurityUtils.getSubject();
|
||||||
|
SecurityManager securityManager = SecurityUtils.getSecurityManager();
|
||||||
super.execute(() -> {
|
super.execute(() -> {
|
||||||
SecurityContext previousContext = SecurityContextHolder.getContext();
|
|
||||||
try {
|
try {
|
||||||
SecurityContextHolder.setContext(context);
|
ThreadContext.bind(securityManager);
|
||||||
|
ThreadContext.bind(subject);
|
||||||
command.run();
|
command.run();
|
||||||
} finally {
|
} finally {
|
||||||
SecurityContextHolder.setContext(previousContext);
|
ThreadContext.unbindSubject();
|
||||||
|
ThreadContext.unbindSecurityManager();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
package org.jeecg.common.util;
|
package org.jeecg.common.util;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jeecg.common.api.CommonAPI;
|
import org.jeecg.common.api.CommonAPI;
|
||||||
@ -12,6 +11,8 @@ import org.jeecg.common.exception.JeecgBoot401Exception;
|
|||||||
import org.jeecg.common.system.util.JwtUtil;
|
import org.jeecg.common.system.util.JwtUtil;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author scott
|
* @Author scott
|
||||||
* @Date 2019/9/23 14:12
|
* @Date 2019/9/23 14:12
|
||||||
@ -109,8 +110,8 @@ public class TokenUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 查询用户信息
|
// 查询用户信息
|
||||||
//LoginUser user = TokenUtils.getLoginUser(username, commonApi, redisUtil);
|
LoginUser user = TokenUtils.getLoginUser(username, commonApi, redisUtil);
|
||||||
LoginUser user = commonApi.getUserByName(username);
|
//LoginUser user = commonApi.getUserByName(username);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
throw new JeecgBoot401Exception("用户不存在!");
|
throw new JeecgBoot401Exception("用户不存在!");
|
||||||
}
|
}
|
||||||
@ -168,11 +169,10 @@ public class TokenUtils {
|
|||||||
//【重要】此处通过redis原生获取缓存用户,是为了解决微服务下system服务挂了,其他服务互调不通问题---
|
//【重要】此处通过redis原生获取缓存用户,是为了解决微服务下system服务挂了,其他服务互调不通问题---
|
||||||
if (redisUtil.hasKey(loginUserKey)) {
|
if (redisUtil.hasKey(loginUserKey)) {
|
||||||
try {
|
try {
|
||||||
Object obj = redisUtil.get(loginUserKey);
|
loginUser = (LoginUser) redisUtil.get(loginUserKey);
|
||||||
loginUser = (LoginUser) obj;
|
|
||||||
//解密用户
|
//解密用户
|
||||||
SensitiveInfoUtil.handlerObject(loginUser, false);
|
SensitiveInfoUtil.handlerObject(loginUser, false);
|
||||||
} catch (Exception e) {
|
} catch (IllegalAccessException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
package org.jeecg.common.util.encryption;
|
package org.jeecg.common.util.encryption;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.shiro.lang.codec.Base64;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import javax.crypto.Cipher;
|
import javax.crypto.Cipher;
|
||||||
import javax.crypto.spec.IvParameterSpec;
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Base64;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AES 工具 (兼容历史 NoPadding + 新 PKCS5Padding)
|
* AES 工具 (兼容历史 NoPadding + 新 PKCS5Padding)
|
||||||
@ -23,7 +23,7 @@ public class AesEncryptUtil {
|
|||||||
SecretKeySpec ks = new SecretKeySpec(KEY.getBytes(StandardCharsets.UTF_8), "AES");
|
SecretKeySpec ks = new SecretKeySpec(KEY.getBytes(StandardCharsets.UTF_8), "AES");
|
||||||
IvParameterSpec ivSpec = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));
|
IvParameterSpec ivSpec = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));
|
||||||
cipher.init(Cipher.DECRYPT_MODE, ks, ivSpec);
|
cipher.init(Cipher.DECRYPT_MODE, ks, ivSpec);
|
||||||
byte[] plain = cipher.doFinal(Base64.getDecoder().decode(cipherBase64));
|
byte[] plain = cipher.doFinal(Base64.decode(cipherBase64));
|
||||||
return new String(plain, StandardCharsets.UTF_8);
|
return new String(plain, StandardCharsets.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ public class AesEncryptUtil {
|
|||||||
SecretKeySpec ks = new SecretKeySpec(KEY.getBytes(StandardCharsets.UTF_8), "AES");
|
SecretKeySpec ks = new SecretKeySpec(KEY.getBytes(StandardCharsets.UTF_8), "AES");
|
||||||
IvParameterSpec ivSpec = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));
|
IvParameterSpec ivSpec = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));
|
||||||
cipher.init(Cipher.DECRYPT_MODE, ks, ivSpec);
|
cipher.init(Cipher.DECRYPT_MODE, ks, ivSpec);
|
||||||
byte[] data = cipher.doFinal(Base64.getDecoder().decode(cipherBase64));
|
byte[] data = cipher.doFinal(Base64.decode(cipherBase64));
|
||||||
return new String(data, StandardCharsets.UTF_8)
|
return new String(data, StandardCharsets.UTF_8)
|
||||||
.replace("\u0000",""); // 旧填充 0
|
.replace("\u0000",""); // 旧填充 0
|
||||||
}
|
}
|
||||||
@ -93,7 +93,7 @@ public class AesEncryptUtil {
|
|||||||
IvParameterSpec ivspec = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));
|
IvParameterSpec ivspec = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
|
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
|
||||||
byte[] encrypted = cipher.doFinal(plaintext);
|
byte[] encrypted = cipher.doFinal(plaintext);
|
||||||
return Base64.getEncoder().encodeToString(encrypted);
|
return Base64.encodeToString(encrypted);
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
throw new IllegalStateException("legacy encrypt error", e);
|
throw new IllegalStateException("legacy encrypt error", e);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,6 +42,10 @@ public class JeecgBaseConfig {
|
|||||||
*/
|
*/
|
||||||
private Firewall firewall;
|
private Firewall firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shiro拦截排除
|
||||||
|
*/
|
||||||
|
private Shiro shiro;
|
||||||
/**
|
/**
|
||||||
* 上传文件配置
|
* 上传文件配置
|
||||||
*/
|
*/
|
||||||
@ -134,6 +138,14 @@ public class JeecgBaseConfig {
|
|||||||
this.signatureSecret = signatureSecret;
|
this.signatureSecret = signatureSecret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Shiro getShiro() {
|
||||||
|
return shiro;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShiro(Shiro shiro) {
|
||||||
|
this.shiro = shiro;
|
||||||
|
}
|
||||||
|
|
||||||
public Path getPath() {
|
public Path getPath() {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
package org.jeecg.config.firewall.interceptor;
|
package org.jeecg.config.firewall.interceptor;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
import org.jeecg.common.api.CommonAPI;
|
import org.jeecg.common.api.CommonAPI;
|
||||||
@ -17,6 +14,9 @@ import org.jeecg.config.JeecgBaseConfig;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.servlet.HandlerInterceptor;
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|||||||
@ -6,13 +6,13 @@ import org.apache.ibatis.executor.Executor;
|
|||||||
import org.apache.ibatis.mapping.MappedStatement;
|
import org.apache.ibatis.mapping.MappedStatement;
|
||||||
import org.apache.ibatis.mapping.SqlCommandType;
|
import org.apache.ibatis.mapping.SqlCommandType;
|
||||||
import org.apache.ibatis.plugin.*;
|
import org.apache.ibatis.plugin.*;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
import org.jeecg.common.config.TenantContext;
|
import org.jeecg.common.config.TenantContext;
|
||||||
import org.jeecg.common.constant.TenantConstant;
|
import org.jeecg.common.constant.TenantConstant;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import org.jeecg.common.util.SpringContextUtils;
|
import org.jeecg.common.util.SpringContextUtils;
|
||||||
import org.jeecg.common.util.TokenUtils;
|
import org.jeecg.common.util.TokenUtils;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
@ -189,7 +189,7 @@ public class MybatisInterceptor implements Interceptor {
|
|||||||
private LoginUser getLoginUser() {
|
private LoginUser getLoginUser() {
|
||||||
LoginUser sysUser = null;
|
LoginUser sysUser = null;
|
||||||
try {
|
try {
|
||||||
sysUser = SecureUtil.currentUser() != null ? SecureUtil.currentUser() : null;
|
sysUser = SecurityUtils.getSubject().getPrincipal() != null ? (LoginUser) SecurityUtils.getSubject().getPrincipal() : null;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
//e.printStackTrace();
|
//e.printStackTrace();
|
||||||
sysUser = null;
|
sysUser = null;
|
||||||
|
|||||||
@ -1,90 +0,0 @@
|
|||||||
package org.jeecg.config.security;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
|
||||||
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* spring authorization server 注册客户端便捷工具类
|
|
||||||
* @author eightmonth@qq.com
|
|
||||||
* @date 2024/3/7 11:22
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class ClientService {
|
|
||||||
|
|
||||||
private RegisteredClientRepository registeredClientRepository;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改客户端token有效期
|
|
||||||
* 认证码、设备码有效期与accessToken有效期保持一致
|
|
||||||
*/
|
|
||||||
public void updateTokenValidation(String clientId, Long accessTokenValidation, Long refreshTokenValidation){
|
|
||||||
RegisteredClient registeredClient = findByClientId(clientId);
|
|
||||||
RegisteredClient.Builder builder = RegisteredClient.from(registeredClient);
|
|
||||||
TokenSettings tokenSettings = TokenSettings.builder()
|
|
||||||
.idTokenSignatureAlgorithm(SignatureAlgorithm.RS256)
|
|
||||||
.accessTokenTimeToLive(Duration.ofSeconds(accessTokenValidation))
|
|
||||||
.accessTokenFormat(OAuth2TokenFormat.SELF_CONTAINED)
|
|
||||||
.reuseRefreshTokens(true)
|
|
||||||
.refreshTokenTimeToLive(Duration.ofSeconds(refreshTokenValidation))
|
|
||||||
.authorizationCodeTimeToLive(Duration.ofSeconds(accessTokenValidation))
|
|
||||||
.deviceCodeTimeToLive(Duration.ofSeconds(accessTokenValidation))
|
|
||||||
.build();
|
|
||||||
builder.tokenSettings(tokenSettings);
|
|
||||||
registeredClientRepository.save(builder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改客户端授权类型
|
|
||||||
* @param clientId
|
|
||||||
* @param grantTypes
|
|
||||||
*/
|
|
||||||
public void updateGrantType(String clientId, Set<AuthorizationGrantType> grantTypes) {
|
|
||||||
RegisteredClient registeredClient = findByClientId(clientId);
|
|
||||||
RegisteredClient.Builder builder = RegisteredClient.from(registeredClient);
|
|
||||||
for (AuthorizationGrantType grantType : grantTypes) {
|
|
||||||
builder.authorizationGrantType(grantType);
|
|
||||||
}
|
|
||||||
registeredClientRepository.save(builder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改客户端重定向uri
|
|
||||||
* @param clientId
|
|
||||||
* @param redirectUris
|
|
||||||
*/
|
|
||||||
public void updateRedirectUris(String clientId, String redirectUris) {
|
|
||||||
RegisteredClient registeredClient = findByClientId(clientId);
|
|
||||||
RegisteredClient.Builder builder = RegisteredClient.from(registeredClient);
|
|
||||||
builder.redirectUri(redirectUris);
|
|
||||||
registeredClientRepository.save(builder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改客户端授权范围
|
|
||||||
* @param clientId
|
|
||||||
* @param scopes
|
|
||||||
*/
|
|
||||||
public void updateScopes(String clientId, Set<String> scopes) {
|
|
||||||
RegisteredClient registeredClient = findByClientId(clientId);
|
|
||||||
RegisteredClient.Builder builder = RegisteredClient.from(registeredClient);
|
|
||||||
for (String scope : scopes) {
|
|
||||||
builder.scope(scope);
|
|
||||||
}
|
|
||||||
registeredClientRepository.save(builder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
public RegisteredClient findByClientId(String clientId) {
|
|
||||||
return registeredClientRepository.findByClientId(clientId);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,80 +0,0 @@
|
|||||||
package org.jeecg.config.security;
|
|
||||||
|
|
||||||
import jakarta.servlet.FilterChain;
|
|
||||||
import jakarta.servlet.ServletException;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletRequestWrapper;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.core.annotation.Order;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 仪盘表请求query体携带的token
|
|
||||||
* @author eightmonth
|
|
||||||
* @date 2024/7/3 14:04
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
@Order(value = Integer.MIN_VALUE)
|
|
||||||
public class CopyTokenFilter extends OncePerRequestFilter {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
|
||||||
throws ServletException, IOException {
|
|
||||||
// 以下为undertow定制代码,如切换其它servlet容器,需要同步更换
|
|
||||||
String token = request.getHeader("Authorization");
|
|
||||||
String bearerToken = request.getParameter("token");
|
|
||||||
String headerBearerToken = request.getHeader("X-Access-Token");
|
|
||||||
String finalToken;
|
|
||||||
|
|
||||||
log.debug("【仪盘表请求query体携带的token】CopyTokenFilter token: {}, bearerToken: {}, headerBearerToken: {}", token, bearerToken, headerBearerToken);
|
|
||||||
|
|
||||||
if (StringUtils.hasText(token)) {
|
|
||||||
finalToken = "bearer " + token;
|
|
||||||
} else if (StringUtils.hasText(bearerToken)) {
|
|
||||||
finalToken = "bearer " + bearerToken;
|
|
||||||
} else if (StringUtils.hasText(headerBearerToken)) {
|
|
||||||
finalToken = "bearer " + headerBearerToken;
|
|
||||||
} else {
|
|
||||||
finalToken = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (finalToken != null) {
|
|
||||||
HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper(request) {
|
|
||||||
@Override
|
|
||||||
public String getHeader(String name) {
|
|
||||||
if ("Authorization".equalsIgnoreCase(name)) {
|
|
||||||
return finalToken;
|
|
||||||
}
|
|
||||||
return super.getHeader(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Enumeration<String> getHeaders(String name) {
|
|
||||||
if ("Authorization".equalsIgnoreCase(name)) {
|
|
||||||
return Collections.enumeration(Collections.singleton(finalToken));
|
|
||||||
}
|
|
||||||
return super.getHeaders(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Enumeration<String> getHeaderNames() {
|
|
||||||
List<String> names = Collections.list(super.getHeaderNames());
|
|
||||||
if (!names.contains("Authorization")) {
|
|
||||||
names.add("Authorization");
|
|
||||||
}
|
|
||||||
return Collections.enumeration(names);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
filterChain.doFilter(wrapper, response);
|
|
||||||
} else {
|
|
||||||
filterChain.doFilter(request, response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
package org.jeecg.config.security;
|
|
||||||
|
|
||||||
import org.jeecg.common.api.CommonAPI;
|
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Lazy;
|
|
||||||
import org.springframework.core.convert.converter.Converter;
|
|
||||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.oauth2.jwt.Jwt;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* token只存储用户名与过期时间
|
|
||||||
* 这里通过取用户名转全量用户信息存储到Security中
|
|
||||||
* @author eightmonth@qq.com
|
|
||||||
* @date 2024/7/15 11:05
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class JeecgAuthenticationConvert implements Converter<Jwt, AbstractAuthenticationToken> {
|
|
||||||
|
|
||||||
@Lazy
|
|
||||||
@Autowired
|
|
||||||
private CommonAPI commonAPI;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AbstractAuthenticationToken convert(Jwt source) {
|
|
||||||
String username = source.getClaims().get("username").toString();
|
|
||||||
LoginUser loginUser = commonAPI.getUserByName(username);
|
|
||||||
return new UsernamePasswordAuthenticationToken(loginUser, null, new ArrayList<>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,135 +0,0 @@
|
|||||||
package org.jeecg.config.security;
|
|
||||||
|
|
||||||
import org.jeecg.common.system.util.JwtUtil;
|
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
import org.springframework.security.oauth2.core.ClaimAccessor;
|
|
||||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
|
||||||
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
|
|
||||||
import org.springframework.security.oauth2.jwt.JwsHeader;
|
|
||||||
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
|
|
||||||
import org.springframework.security.oauth2.jwt.JwtEncoder;
|
|
||||||
import org.springframework.security.oauth2.jwt.JwtEncoderParameters;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.token.*;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.time.temporal.Temporal;
|
|
||||||
import java.time.temporal.TemporalUnit;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author eightmonth@qq.com
|
|
||||||
* @date 2024/7/11 17:10
|
|
||||||
*/
|
|
||||||
public class JeecgOAuth2AccessTokenGenerator implements OAuth2TokenGenerator<OAuth2AccessToken> {
|
|
||||||
private final JwtEncoder jwtEncoder;
|
|
||||||
|
|
||||||
private OAuth2TokenCustomizer<OAuth2TokenClaimsContext> accessTokenCustomizer;
|
|
||||||
|
|
||||||
public JeecgOAuth2AccessTokenGenerator(JwtEncoder jwtEncoder) {
|
|
||||||
this.jwtEncoder = jwtEncoder;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public OAuth2AccessToken generate(OAuth2TokenContext context) {
|
|
||||||
if (!OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType())) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
String issuer = null;
|
|
||||||
if (context.getAuthorizationServerContext() != null) {
|
|
||||||
issuer = context.getAuthorizationServerContext().getIssuer();
|
|
||||||
}
|
|
||||||
RegisteredClient registeredClient = context.getRegisteredClient();
|
|
||||||
|
|
||||||
Instant issuedAt = Instant.now();
|
|
||||||
Instant expiresAt = issuedAt.plusMillis(JwtUtil.EXPIRE_TIME);
|
|
||||||
|
|
||||||
OAuth2TokenClaimsSet.Builder claimsBuilder = OAuth2TokenClaimsSet.builder();
|
|
||||||
if (StringUtils.hasText(issuer)) {
|
|
||||||
claimsBuilder.issuer(issuer);
|
|
||||||
}
|
|
||||||
claimsBuilder
|
|
||||||
.subject(context.getPrincipal().getName())
|
|
||||||
.audience(Collections.singletonList(registeredClient.getClientId()))
|
|
||||||
.issuedAt(issuedAt)
|
|
||||||
.expiresAt(expiresAt)
|
|
||||||
.notBefore(issuedAt)
|
|
||||||
.id(UUID.randomUUID().toString());
|
|
||||||
if (!CollectionUtils.isEmpty(context.getAuthorizedScopes())) {
|
|
||||||
claimsBuilder.claim(OAuth2ParameterNames.SCOPE, context.getAuthorizedScopes());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.accessTokenCustomizer != null) {
|
|
||||||
OAuth2TokenClaimsContext.Builder accessTokenContextBuilder = OAuth2TokenClaimsContext.with(claimsBuilder)
|
|
||||||
.registeredClient(context.getRegisteredClient())
|
|
||||||
.principal(context.getPrincipal())
|
|
||||||
.authorizationServerContext(context.getAuthorizationServerContext())
|
|
||||||
.authorizedScopes(context.getAuthorizedScopes())
|
|
||||||
.tokenType(context.getTokenType())
|
|
||||||
.authorizationGrantType(context.getAuthorizationGrantType());
|
|
||||||
if (context.getAuthorization() != null) {
|
|
||||||
accessTokenContextBuilder.authorization(context.getAuthorization());
|
|
||||||
}
|
|
||||||
if (context.getAuthorizationGrant() != null) {
|
|
||||||
accessTokenContextBuilder.authorizationGrant(context.getAuthorizationGrant());
|
|
||||||
}
|
|
||||||
|
|
||||||
OAuth2TokenClaimsContext accessTokenContext = accessTokenContextBuilder.build();
|
|
||||||
this.accessTokenCustomizer.customize(accessTokenContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
OAuth2TokenClaimsSet accessTokenClaimsSet = claimsBuilder.build();
|
|
||||||
OAuth2AuthorizationGrantAuthenticationToken oAuth2ResourceOwnerBaseAuthenticationToken = context.getAuthorizationGrant();
|
|
||||||
String username = (String) oAuth2ResourceOwnerBaseAuthenticationToken.getAdditionalParameters().get("username");
|
|
||||||
String tokenValue = jwtEncoder.encode(JwtEncoderParameters.from(JwsHeader.with(SignatureAlgorithm.ES256).keyId("jeecg").build(),
|
|
||||||
JwtClaimsSet.builder().claim("username", username).expiresAt(expiresAt).build())).getTokenValue();
|
|
||||||
|
|
||||||
//此处可以做改造将tokenValue随机数换成用户信息,方便后续多系统token互通认证(通过解密token得到username)
|
|
||||||
return new OAuth2AccessTokenClaims(OAuth2AccessToken.TokenType.BEARER, tokenValue,
|
|
||||||
accessTokenClaimsSet.getIssuedAt(), accessTokenClaimsSet.getExpiresAt(), context.getAuthorizedScopes(),
|
|
||||||
accessTokenClaimsSet.getClaims());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the {@link OAuth2TokenCustomizer} that customizes the
|
|
||||||
* {@link OAuth2TokenClaimsContext#getClaims() claims} for the
|
|
||||||
* {@link OAuth2AccessToken}.
|
|
||||||
* @param accessTokenCustomizer the {@link OAuth2TokenCustomizer} that customizes the
|
|
||||||
* claims for the {@code OAuth2AccessToken}
|
|
||||||
*/
|
|
||||||
public void setAccessTokenCustomizer(OAuth2TokenCustomizer<OAuth2TokenClaimsContext> accessTokenCustomizer) {
|
|
||||||
Assert.notNull(accessTokenCustomizer, "accessTokenCustomizer cannot be null");
|
|
||||||
this.accessTokenCustomizer = accessTokenCustomizer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class OAuth2AccessTokenClaims extends OAuth2AccessToken implements ClaimAccessor {
|
|
||||||
|
|
||||||
private final Map<String, Object> claims;
|
|
||||||
|
|
||||||
private OAuth2AccessTokenClaims(TokenType tokenType, String tokenValue, Instant issuedAt, Instant expiresAt,
|
|
||||||
Set<String> scopes, Map<String, Object> claims) {
|
|
||||||
super(tokenType, tokenValue, issuedAt, expiresAt, scopes);
|
|
||||||
this.claims = claims;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Object> getClaims() {
|
|
||||||
return this.claims;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,104 +0,0 @@
|
|||||||
package org.jeecg.config.security;
|
|
||||||
|
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.jeecg.common.api.CommonAPI;
|
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
|
||||||
import org.jeecg.common.util.RedisUtil;
|
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Lazy;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.util.PatternMatchUtils;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* spring authorization server自定义权限处理,根据@PreAuthorize注解,判断当前用户是否具备权限
|
|
||||||
* @author EightMonth
|
|
||||||
* @date 2024/1/10 17:00
|
|
||||||
*/
|
|
||||||
@Service("jps")
|
|
||||||
@Slf4j
|
|
||||||
public class JeecgPermissionService {
|
|
||||||
private final String SPLIT = "::";
|
|
||||||
private final String PERM_PREFIX = "jps" + SPLIT;
|
|
||||||
|
|
||||||
@Lazy
|
|
||||||
@Autowired
|
|
||||||
private CommonAPI commonAPI;
|
|
||||||
@Autowired
|
|
||||||
private RedisUtil redisUtil;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断接口是否有任意xxx,xxx权限
|
|
||||||
* @param permissions 权限
|
|
||||||
* @return {boolean}
|
|
||||||
*/
|
|
||||||
public boolean requiresPermissions(String... permissions) {
|
|
||||||
if (ArrayUtil.isEmpty(permissions)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
LoginUser loginUser = SecureUtil.currentUser();
|
|
||||||
|
|
||||||
Object cache = redisUtil.get(buildKey("permission", loginUser.getId()));
|
|
||||||
Set<String> permissionList;
|
|
||||||
if (Objects.nonNull(cache)) {
|
|
||||||
permissionList = (Set<String>) cache;
|
|
||||||
} else {
|
|
||||||
permissionList = commonAPI.queryUserAuths(loginUser.getId());
|
|
||||||
redisUtil.set(buildKey("permission", loginUser.getId()), permissionList);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean pass = permissionList.stream().filter(StringUtils::hasText)
|
|
||||||
.anyMatch(x -> PatternMatchUtils.simpleMatch(permissions, x));
|
|
||||||
if (!pass) {
|
|
||||||
log.error("权限不足,缺少权限:"+ Arrays.toString(permissions));
|
|
||||||
}
|
|
||||||
return pass;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断接口是否有任意xxx,xxx角色
|
|
||||||
* @param roles 角色
|
|
||||||
* @return {boolean}
|
|
||||||
*/
|
|
||||||
public boolean requiresRoles(String... roles) {
|
|
||||||
if (ArrayUtil.isEmpty(roles)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
LoginUser loginUser = SecureUtil.currentUser();
|
|
||||||
|
|
||||||
Object cache = redisUtil.get(buildKey("role", loginUser.getUsername()));
|
|
||||||
Set<String> roleList;
|
|
||||||
if (Objects.nonNull(cache)) {
|
|
||||||
roleList = (Set<String>) cache;
|
|
||||||
} else {
|
|
||||||
roleList = commonAPI.queryUserRoles(loginUser.getUsername());
|
|
||||||
redisUtil.set(buildKey("role", loginUser.getUsername()), roleList);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean pass = roleList.stream().filter(StringUtils::hasText)
|
|
||||||
.anyMatch(x -> PatternMatchUtils.simpleMatch(roles, x));
|
|
||||||
if (!pass) {
|
|
||||||
log.error("权限不足,缺少角色:" + Arrays.toString(roles));
|
|
||||||
}
|
|
||||||
return pass;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 由于缓存key是以人的维度,角色列表、权限列表在值中,jeecg是以权限列表绑定在角色上,形成的权限集合
|
|
||||||
* 权限发生变更时,需要清理全部人的权限缓存
|
|
||||||
*/
|
|
||||||
public void clearCache() {
|
|
||||||
redisUtil.removeAll(PERM_PREFIX);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String buildKey(String type, String username) {
|
|
||||||
return PERM_PREFIX + type + SPLIT + username;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
package org.jeecg.config.security;
|
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* spring authorization server 自定义redis保存授权范围信息
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class JeecgRedisOAuth2AuthorizationConsentService implements OAuth2AuthorizationConsentService {
|
|
||||||
|
|
||||||
private final RedisTemplate<String, Object> redisTemplate;
|
|
||||||
|
|
||||||
private final static Long TIMEOUT = 10L;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save(OAuth2AuthorizationConsent authorizationConsent) {
|
|
||||||
Assert.notNull(authorizationConsent, "authorizationConsent cannot be null");
|
|
||||||
|
|
||||||
redisTemplate.opsForValue().set(buildKey(authorizationConsent), authorizationConsent, TIMEOUT,
|
|
||||||
TimeUnit.MINUTES);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void remove(OAuth2AuthorizationConsent authorizationConsent) {
|
|
||||||
Assert.notNull(authorizationConsent, "authorizationConsent cannot be null");
|
|
||||||
redisTemplate.delete(buildKey(authorizationConsent));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public OAuth2AuthorizationConsent findById(String registeredClientId, String principalName) {
|
|
||||||
Assert.hasText(registeredClientId, "registeredClientId cannot be empty");
|
|
||||||
Assert.hasText(principalName, "principalName cannot be empty");
|
|
||||||
return (OAuth2AuthorizationConsent) redisTemplate.opsForValue()
|
|
||||||
.get(buildKey(registeredClientId, principalName));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String buildKey(String registeredClientId, String principalName) {
|
|
||||||
return "token:consent:" + registeredClientId + ":" + principalName;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String buildKey(OAuth2AuthorizationConsent authorizationConsent) {
|
|
||||||
return buildKey(authorizationConsent.getRegisteredClientId(), authorizationConsent.getPrincipalName());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,192 +0,0 @@
|
|||||||
package org.jeecg.config.security;
|
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
|
||||||
import jakarta.annotation.PostConstruct;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
|
||||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
|
||||||
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
|
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationCode;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
import java.time.temporal.ChronoUnit;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* spring authorization server自定义redis保存认证信息
|
|
||||||
* @author EightMonth
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class JeecgRedisOAuth2AuthorizationService implements OAuth2AuthorizationService{
|
|
||||||
|
|
||||||
private final static Long TIMEOUT = 10L;
|
|
||||||
|
|
||||||
private static final String AUTHORIZATION = "token";
|
|
||||||
|
|
||||||
private final RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RedisConnectionFactory redisConnectionFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 因为保存sas的认证信息至redis,无法使用jeecg对redisTemplate的某些设置。
|
|
||||||
* 如果在使用时修改redisTemplate属性,会发生线程安全问题,最终容易引起系统无法正常运行。
|
|
||||||
* 所以重新建了一个redis client给到sas操作redis,并且该redis实例不注入spring 容器中
|
|
||||||
*/
|
|
||||||
@PostConstruct
|
|
||||||
public void initSasRedis() {
|
|
||||||
redisTemplate.setValueSerializer(RedisSerializer.java());
|
|
||||||
redisTemplate.setConnectionFactory(redisConnectionFactory);
|
|
||||||
redisTemplate.afterPropertiesSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save(OAuth2Authorization authorization) {
|
|
||||||
Assert.notNull(authorization, "authorization cannot be null");
|
|
||||||
|
|
||||||
if (isState(authorization)) {
|
|
||||||
String token = authorization.getAttribute("state");
|
|
||||||
redisTemplate.opsForValue().set(buildKey(OAuth2ParameterNames.STATE, token), authorization, TIMEOUT,
|
|
||||||
TimeUnit.MINUTES);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isCode(authorization)) {
|
|
||||||
OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCode = authorization
|
|
||||||
.getToken(OAuth2AuthorizationCode.class);
|
|
||||||
OAuth2AuthorizationCode authorizationCodeToken = authorizationCode.getToken();
|
|
||||||
long between = ChronoUnit.MINUTES.between(authorizationCodeToken.getIssuedAt(),
|
|
||||||
authorizationCodeToken.getExpiresAt());
|
|
||||||
redisTemplate.opsForValue().set(buildKey(OAuth2ParameterNames.CODE, authorizationCodeToken.getTokenValue()),
|
|
||||||
authorization, between, TimeUnit.MINUTES);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isRefreshToken(authorization)) {
|
|
||||||
OAuth2RefreshToken refreshToken = authorization.getRefreshToken().getToken();
|
|
||||||
long between = ChronoUnit.SECONDS.between(refreshToken.getIssuedAt(), refreshToken.getExpiresAt());
|
|
||||||
redisTemplate.opsForValue().set(buildKey(OAuth2ParameterNames.REFRESH_TOKEN, refreshToken.getTokenValue()),
|
|
||||||
authorization, between, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isAccessToken(authorization)) {
|
|
||||||
OAuth2AccessToken accessToken = authorization.getAccessToken().getToken();
|
|
||||||
long between = ChronoUnit.SECONDS.between(accessToken.getIssuedAt(), accessToken.getExpiresAt());
|
|
||||||
redisTemplate.opsForValue().set(buildKey(OAuth2ParameterNames.ACCESS_TOKEN, accessToken.getTokenValue()),
|
|
||||||
authorization, between, TimeUnit.SECONDS);
|
|
||||||
|
|
||||||
// 扩展记录 access-token 、username 的关系 1::token::username::admin::xxx
|
|
||||||
String tokenUsername = String.format("%s::%s::%s", AUTHORIZATION, authorization.getPrincipalName(), accessToken.getTokenValue());
|
|
||||||
redisTemplate.opsForValue().set(tokenUsername, accessToken.getTokenValue(), between, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void remove(OAuth2Authorization authorization) {
|
|
||||||
Assert.notNull(authorization, "authorization cannot be null");
|
|
||||||
|
|
||||||
List<String> keys = new ArrayList<>();
|
|
||||||
if (isState(authorization)) {
|
|
||||||
String token = authorization.getAttribute("state");
|
|
||||||
keys.add(buildKey(OAuth2ParameterNames.STATE, token));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isCode(authorization)) {
|
|
||||||
OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCode = authorization
|
|
||||||
.getToken(OAuth2AuthorizationCode.class);
|
|
||||||
OAuth2AuthorizationCode authorizationCodeToken = authorizationCode.getToken();
|
|
||||||
keys.add(buildKey(OAuth2ParameterNames.CODE, authorizationCodeToken.getTokenValue()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isRefreshToken(authorization)) {
|
|
||||||
OAuth2RefreshToken refreshToken = authorization.getRefreshToken().getToken();
|
|
||||||
keys.add(buildKey(OAuth2ParameterNames.REFRESH_TOKEN, refreshToken.getTokenValue()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isAccessToken(authorization)) {
|
|
||||||
OAuth2AccessToken accessToken = authorization.getAccessToken().getToken();
|
|
||||||
keys.add(buildKey(OAuth2ParameterNames.ACCESS_TOKEN, accessToken.getTokenValue()));
|
|
||||||
|
|
||||||
// 扩展记录 access-token 、username 的关系 1::token::username::admin::xxx
|
|
||||||
String key = String.format("%s::%s::%s", AUTHORIZATION, authorization.getPrincipalName(), accessToken.getTokenValue());
|
|
||||||
keys.add(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
redisTemplate.delete(keys);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public OAuth2Authorization findById(String id) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public OAuth2Authorization findByToken(String token, @Nullable OAuth2TokenType tokenType) {
|
|
||||||
Assert.hasText(token, "token cannot be empty");
|
|
||||||
Assert.notNull(tokenType, "tokenType cannot be empty");
|
|
||||||
return (OAuth2Authorization) redisTemplate.opsForValue().get(buildKey(tokenType.getValue(), token));
|
|
||||||
}
|
|
||||||
|
|
||||||
private String buildKey(String type, String id) {
|
|
||||||
return String.format("%s::%s::%s", AUTHORIZATION, type, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isState(OAuth2Authorization authorization) {
|
|
||||||
return Objects.nonNull(authorization.getAttribute("state"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isCode(OAuth2Authorization authorization) {
|
|
||||||
OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCode = authorization
|
|
||||||
.getToken(OAuth2AuthorizationCode.class);
|
|
||||||
return Objects.nonNull(authorizationCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isRefreshToken(OAuth2Authorization authorization) {
|
|
||||||
return Objects.nonNull(authorization.getRefreshToken());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isAccessToken(OAuth2Authorization authorization) {
|
|
||||||
return Objects.nonNull(authorization.getAccessToken());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 扩展方法根据 username 查询是否存在存储的
|
|
||||||
* @param authentication
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public void removeByUsername(Authentication authentication) {
|
|
||||||
// 根据 username查询对应access-token
|
|
||||||
String authenticationName = authentication.getName();
|
|
||||||
|
|
||||||
// 扩展记录 access-token 、username 的关系 1::token::username::admin::xxx
|
|
||||||
String tokenUsernameKey = String.format("%s::%s::*", AUTHORIZATION, authenticationName);
|
|
||||||
Set<String> keys = redisTemplate.keys(tokenUsernameKey);
|
|
||||||
if (CollUtil.isEmpty(keys)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Object> tokenList = redisTemplate.opsForValue().multiGet(keys);
|
|
||||||
|
|
||||||
for (Object token : tokenList) {
|
|
||||||
// 根据token 查询存储的 OAuth2Authorization
|
|
||||||
OAuth2Authorization authorization = this.findByToken((String) token, OAuth2TokenType.ACCESS_TOKEN);
|
|
||||||
// 根据 OAuth2Authorization 删除相关令牌
|
|
||||||
this.remove(authorization);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
package org.jeecg.config.security;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录模式
|
|
||||||
* @author EightMonth
|
|
||||||
* @date 2024/1/10 17:43
|
|
||||||
*/
|
|
||||||
public class LoginType {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 密码模式
|
|
||||||
*/
|
|
||||||
public static final String PASSWORD = "password";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 手机号+验证码模式
|
|
||||||
*/
|
|
||||||
public static final String PHONE = "phone";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* app登录
|
|
||||||
*/
|
|
||||||
public static final String APP = "app";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 扫码登录
|
|
||||||
*/
|
|
||||||
public static final String SCAN = "scan";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 所有联合登录,比如github\钉钉\企业微信\微信
|
|
||||||
*/
|
|
||||||
public static final String SOCIAL = "social";
|
|
||||||
|
|
||||||
public static final String SELF = "self";
|
|
||||||
}
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
package org.jeecg.config.security;
|
|
||||||
|
|
||||||
import jakarta.servlet.FilterChain;
|
|
||||||
import jakarta.servlet.ServletException;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import org.jeecg.common.system.util.JwtUtil;
|
|
||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
|
||||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
|
|
||||||
import org.springframework.security.oauth2.server.resource.BearerTokenErrors;
|
|
||||||
import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当用户被强退时,使客户端token失效
|
|
||||||
* @author eightmonth@qq.com
|
|
||||||
* @date 2024/3/7 17:30
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class RedisTokenValidationFilter extends OncePerRequestFilter {
|
|
||||||
private OAuth2AuthorizationService authorizationService;
|
|
||||||
private JwtDecoder jwtDecoder;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
|
||||||
// 从请求中获取token
|
|
||||||
DefaultBearerTokenResolver defaultBearerTokenResolver = new DefaultBearerTokenResolver();
|
|
||||||
String token = defaultBearerTokenResolver.resolve(request);
|
|
||||||
|
|
||||||
|
|
||||||
if (Objects.nonNull(token)) {
|
|
||||||
// 检查认证信息是否已被清除,如果已被清除,则令该token失效
|
|
||||||
OAuth2Authorization oAuth2Authorization = authorizationService.findByToken(token, OAuth2TokenType.ACCESS_TOKEN);
|
|
||||||
if (Objects.isNull(oAuth2Authorization)) {
|
|
||||||
throw new OAuth2AuthenticationException(BearerTokenErrors.invalidToken("认证信息已失效,请重新登录"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filterChain.doFilter(request, response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,310 +0,0 @@
|
|||||||
package org.jeecg.config.security;
|
|
||||||
|
|
||||||
import com.nimbusds.jose.jwk.Curve;
|
|
||||||
import com.nimbusds.jose.jwk.ECKey;
|
|
||||||
import com.nimbusds.jose.jwk.JWKSet;
|
|
||||||
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
|
|
||||||
import com.nimbusds.jose.jwk.source.JWKSource;
|
|
||||||
import com.nimbusds.jose.proc.SecurityContext;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.jeecg.common.system.util.JwtUtil;
|
|
||||||
import org.jeecg.config.security.app.AppGrantAuthenticationConvert;
|
|
||||||
import org.jeecg.config.security.app.AppGrantAuthenticationProvider;
|
|
||||||
import org.jeecg.config.security.password.PasswordGrantAuthenticationConvert;
|
|
||||||
import org.jeecg.config.security.password.PasswordGrantAuthenticationProvider;
|
|
||||||
import org.jeecg.config.security.phone.PhoneGrantAuthenticationConvert;
|
|
||||||
import org.jeecg.config.security.phone.PhoneGrantAuthenticationProvider;
|
|
||||||
import org.jeecg.config.security.social.SocialGrantAuthenticationConvert;
|
|
||||||
import org.jeecg.config.security.social.SocialGrantAuthenticationProvider;
|
|
||||||
import org.jeecg.config.shiro.ignore.InMemoryIgnoreAuth;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.core.annotation.Order;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
|
||||||
import org.springframework.security.config.Customizer;
|
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
|
||||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
|
||||||
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
||||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
|
||||||
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.token.*;
|
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
|
||||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
|
||||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
|
||||||
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
|
||||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
import org.springframework.web.cors.CorsConfiguration;
|
|
||||||
|
|
||||||
import java.security.KeyPair;
|
|
||||||
import java.security.KeyPairGenerator;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.security.interfaces.ECPrivateKey;
|
|
||||||
import java.security.interfaces.ECPublicKey;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* spring authorization server核心配置
|
|
||||||
* @author eightmonth@qq.com
|
|
||||||
* @date 2024/1/2 9:29
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
@EnableWebSecurity
|
|
||||||
@EnableMethodSecurity
|
|
||||||
@AllArgsConstructor
|
|
||||||
@Slf4j
|
|
||||||
public class SecurityConfig {
|
|
||||||
|
|
||||||
private JdbcTemplate jdbcTemplate;
|
|
||||||
private OAuth2AuthorizationService authorizationService;
|
|
||||||
private JeecgAuthenticationConvert jeecgAuthenticationConvert;
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@Order(1)
|
|
||||||
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http)
|
|
||||||
throws Exception {
|
|
||||||
// 使用新的配置方式替代弃用的applyDefaultSecurity
|
|
||||||
http.securityMatcher(new AntPathRequestMatcher("/oauth2/**"))
|
|
||||||
.authorizeHttpRequests(authorize ->
|
|
||||||
authorize.anyRequest().authenticated()
|
|
||||||
)
|
|
||||||
.csrf(csrf -> csrf.disable())
|
|
||||||
.with(new OAuth2AuthorizationServerConfigurer(), oauth2 -> {
|
|
||||||
oauth2
|
|
||||||
.tokenEndpoint(tokenEndpoint -> tokenEndpoint
|
|
||||||
.accessTokenRequestConverter(new PasswordGrantAuthenticationConvert())
|
|
||||||
.authenticationProvider(new PasswordGrantAuthenticationProvider(authorizationService, tokenGenerator()))
|
|
||||||
)
|
|
||||||
.tokenEndpoint(tokenEndpoint -> tokenEndpoint
|
|
||||||
.accessTokenRequestConverter(new PhoneGrantAuthenticationConvert())
|
|
||||||
.authenticationProvider(new PhoneGrantAuthenticationProvider(authorizationService, tokenGenerator()))
|
|
||||||
)
|
|
||||||
.tokenEndpoint(tokenEndpoint -> tokenEndpoint
|
|
||||||
.accessTokenRequestConverter(new AppGrantAuthenticationConvert())
|
|
||||||
.authenticationProvider(new AppGrantAuthenticationProvider(authorizationService, tokenGenerator()))
|
|
||||||
)
|
|
||||||
.tokenEndpoint(tokenEndpoint -> tokenEndpoint
|
|
||||||
.accessTokenRequestConverter(new SocialGrantAuthenticationConvert())
|
|
||||||
.authenticationProvider(new SocialGrantAuthenticationProvider(authorizationService, tokenGenerator()))
|
|
||||||
)
|
|
||||||
//开启OpenID Connect 1.0(其中oidc为OpenID Connect的缩写)。 访问 /.well-known/openid-configuration即可获取认证信息
|
|
||||||
.oidc(Customizer.withDefaults());
|
|
||||||
});
|
|
||||||
|
|
||||||
//请求接口异常处理:无Token和Token无效的情况
|
|
||||||
http.exceptionHandling(exceptions -> exceptions
|
|
||||||
.authenticationEntryPoint((request, response, authException) -> {
|
|
||||||
// 记录详细的异常信息 - 未认证
|
|
||||||
log.error("接口访问失败(未认证),请求路径:{},错误信息:{}", request.getRequestURI(), authException.getMessage(), authException);
|
|
||||||
JwtUtil.responseError(response, 401, "Token无效或已过期");
|
|
||||||
})
|
|
||||||
.accessDeniedHandler((request, response, accessDeniedException) -> {
|
|
||||||
// 记录详细的异常信息 - token无效或权限不足
|
|
||||||
log.error("接口访问失败(token无效或权限不足),请求路径:{},错误信息:{}", request.getRequestURI(), accessDeniedException.getMessage(), accessDeniedException);
|
|
||||||
JwtUtil.responseError(response, 403, "权限不足");
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return http.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@Order(2)
|
|
||||||
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)
|
|
||||||
throws Exception {
|
|
||||||
http
|
|
||||||
//设置所有请求都需要认证,未认证的请求都被重定向到login页面进行登录
|
|
||||||
.authorizeHttpRequests((authorize) -> authorize
|
|
||||||
.requestMatchers(InMemoryIgnoreAuth.get().stream().map(AntPathRequestMatcher::antMatcher).toList().toArray(new AntPathRequestMatcher[0])).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/cas/client/validateLogin")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/randomImage/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/checkCaptcha")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/login")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/mLogin")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/logout")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/thirdLogin/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/getEncryptedString")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/sms")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/phoneLogin")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/user/checkOnlyUser")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/user/register")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/user/phoneVerification")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/user/passwordChange")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/auth/2step-code")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/common/static/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/common/pdf/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/generic/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/getLoginQrcode/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/getQrcodeToken/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/checkAuth")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/doc.html")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.js")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.css")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.html")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.svg")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.pdf")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.jpg")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.png")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.gif")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.ico")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.ttf")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.woff")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.woff2")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/druid/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/swagger-ui.html")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/swagger**/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/webjars/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/v3/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/WW_verify*")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/annountCement/show/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/api/getUserInfo")).permitAll()
|
|
||||||
|
|
||||||
//积木报表排除
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/jmreport/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.js.map")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.css.map")).permitAll()
|
|
||||||
//积木BI大屏和仪表盘排除
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/drag/view")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/drag/onlDragDatasetHead/getLoginUser")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/drag/page/queryById")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/drag/page/addVisitsNumber")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/drag/page/queryTemplateList")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/drag/share/view/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/drag/onlDragDatasetHead/getAllChartData")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/drag/onlDragDatasetHead/getTotalData")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/drag/mock/json/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/jimubi/view")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/jimubi/share/view/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/drag/onlDragDatasetHead/getMapDataByCode")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/drag/onlDragDatasetHead/getTotalDataByCompId")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/drag/onlDragDatasetHead/queryAllById")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/drag/onlDragDatasetHead/getDictByCodes")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/dragChannelSocket/**")).permitAll()
|
|
||||||
//大屏模板例子
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/test/bigScreen/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/bigscreen/template1/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/bigscreen/template1/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/websocket/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/newsWebsocket/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/vxeSocket/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/test/seata/**")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/error")).permitAll()
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/openapi/call/**")).permitAll()
|
|
||||||
// APP版本信息
|
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/version/app3version")).permitAll()
|
|
||||||
.anyRequest().authenticated()
|
|
||||||
)
|
|
||||||
.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
|
|
||||||
.cors(cors -> cors
|
|
||||||
.configurationSource(req -> {
|
|
||||||
CorsConfiguration config = new CorsConfiguration();
|
|
||||||
config.applyPermitDefaultValues();
|
|
||||||
config.setAllowedMethods(Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
|
|
||||||
return config;
|
|
||||||
}))
|
|
||||||
.csrf(AbstractHttpConfigurer::disable)
|
|
||||||
// 配置OAuth2资源服务器,并添加JWT异常处理
|
|
||||||
.oauth2ResourceServer(oauth2 -> oauth2
|
|
||||||
.jwt(jwt -> jwt.jwtAuthenticationConverter(jeecgAuthenticationConvert))
|
|
||||||
.authenticationEntryPoint((request, response, authException) -> {
|
|
||||||
// 处理JWT解析失败的情况
|
|
||||||
log.error("JWT验证失败,请求路径:{},错误信息:{}", request.getRequestURI(), authException.getMessage(), authException);
|
|
||||||
JwtUtil.responseError(response, 401, "Token无效或已过期");
|
|
||||||
})
|
|
||||||
.accessDeniedHandler((request, response, accessDeniedException) -> {
|
|
||||||
// 处理权限不足的情况
|
|
||||||
log.error("权限验证失败,请求路径:{},错误信息:{}", request.getRequestURI(), accessDeniedException.getMessage(), accessDeniedException);
|
|
||||||
JwtUtil.responseError(response, 403, "权限不足");
|
|
||||||
})
|
|
||||||
)
|
|
||||||
// 全局异常处理
|
|
||||||
.exceptionHandling(exceptions -> exceptions
|
|
||||||
.authenticationEntryPoint((request, response, authException) -> {
|
|
||||||
// 记录详细的异常信息 - 未认证
|
|
||||||
log.error("接口访问失败(未认证),请求路径:{},错误信息:{}", request.getRequestURI(), authException.getMessage(), authException);
|
|
||||||
JwtUtil.responseError(response, 401, "Token无效或已过期");
|
|
||||||
})
|
|
||||||
.accessDeniedHandler((request, response, accessDeniedException) -> {
|
|
||||||
// 记录详细的异常信息 - token无效或权限不足
|
|
||||||
log.error("接口访问失败(token无效或权限不足),请求路径:{},错误信息:{}", request.getRequestURI(), accessDeniedException.getMessage(), accessDeniedException);
|
|
||||||
JwtUtil.responseError(response, 403, "权限不足");
|
|
||||||
})
|
|
||||||
);
|
|
||||||
return http.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数据库保存注册客户端信息
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public RegisteredClientRepository registeredClientRepository() {
|
|
||||||
return new JdbcRegisteredClientRepository(jdbcTemplate);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*配置 JWK,为JWT(id_token)提供加密密钥,用于加密/解密或签名/验签
|
|
||||||
* JWK详细见:https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key-41
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
@SneakyThrows
|
|
||||||
public JWKSource<SecurityContext> jwkSource() {
|
|
||||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
|
|
||||||
// 如果不设置secureRandom,会存在一个问题,当应用重启后,原有的token将会全部失效,因为重启的keyPair与之前已经不同
|
|
||||||
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
|
|
||||||
// 重要!生产环境需要修改!
|
|
||||||
secureRandom.setSeed("jeecg".getBytes());
|
|
||||||
keyPairGenerator.initialize(256, secureRandom);
|
|
||||||
KeyPair keyPair = keyPairGenerator.generateKeyPair();
|
|
||||||
ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic();
|
|
||||||
ECPrivateKey privateKey = (ECPrivateKey) keyPair.getPrivate();
|
|
||||||
|
|
||||||
ECKey jwk = new ECKey.Builder(Curve.P_256, publicKey)
|
|
||||||
.privateKey(privateKey)
|
|
||||||
.keyID("jeecg")
|
|
||||||
.build();
|
|
||||||
JWKSet jwkSet = new JWKSet(jwk);
|
|
||||||
return new ImmutableJWKSet<>(jwkSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public PasswordEncoder passwordEncoder() {
|
|
||||||
return NoOpPasswordEncoder.getInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 配置jwt解析器
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
|
|
||||||
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*配置token生成器
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
OAuth2TokenGenerator<?> tokenGenerator() {
|
|
||||||
JwtGenerator jwtGenerator = new JwtGenerator(new NimbusJwtEncoder(jwkSource()));
|
|
||||||
OAuth2AccessTokenGenerator accessTokenGenerator = new OAuth2AccessTokenGenerator();
|
|
||||||
OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator();
|
|
||||||
return new DelegatingOAuth2TokenGenerator(
|
|
||||||
new JeecgOAuth2AccessTokenGenerator(new NimbusJwtEncoder(jwkSource())),
|
|
||||||
new OAuth2RefreshTokenGenerator()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
package org.jeecg.config.security.app;
|
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import org.jeecg.config.security.LoginType;
|
|
||||||
import org.jeecg.config.security.password.PasswordGrantAuthenticationToken;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
|
||||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
|
||||||
import org.springframework.util.MultiValueMap;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* APP模式认证转换器
|
|
||||||
* @author EightMonth
|
|
||||||
* @date 2024/1/1
|
|
||||||
*/
|
|
||||||
public class AppGrantAuthenticationConvert implements AuthenticationConverter {
|
|
||||||
@Override
|
|
||||||
public Authentication convert(HttpServletRequest request) {
|
|
||||||
|
|
||||||
String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
|
|
||||||
if (!LoginType.APP.equals(grantType)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();
|
|
||||||
|
|
||||||
//从request中提取请求参数,然后存入MultiValueMap<String, String>
|
|
||||||
MultiValueMap<String, String> parameters = getParameters(request);
|
|
||||||
|
|
||||||
// username (REQUIRED)
|
|
||||||
String username = parameters.getFirst(OAuth2ParameterNames.USERNAME);
|
|
||||||
if (!StringUtils.hasText(username) ||
|
|
||||||
parameters.get(OAuth2ParameterNames.USERNAME).size() != 1) {
|
|
||||||
throw new OAuth2AuthenticationException("无效请求,用户名不能为空!");
|
|
||||||
}
|
|
||||||
String password = parameters.getFirst(OAuth2ParameterNames.PASSWORD);
|
|
||||||
if (!StringUtils.hasText(password) ||
|
|
||||||
parameters.get(OAuth2ParameterNames.PASSWORD).size() != 1) {
|
|
||||||
throw new OAuth2AuthenticationException("无效请求,密码不能为空!");
|
|
||||||
}
|
|
||||||
|
|
||||||
//收集要传入PasswordGrantAuthenticationToken构造方法的参数,
|
|
||||||
//该参数接下来在PasswordGrantAuthenticationProvider中使用
|
|
||||||
Map<String, Object> additionalParameters = new HashMap<>();
|
|
||||||
//遍历从request中提取的参数,排除掉grant_type、client_id、code等字段参数,其他参数收集到additionalParameters中
|
|
||||||
parameters.forEach((key, value) -> {
|
|
||||||
if (!key.equals(OAuth2ParameterNames.GRANT_TYPE) &&
|
|
||||||
!key.equals(OAuth2ParameterNames.CLIENT_ID) &&
|
|
||||||
!key.equals(OAuth2ParameterNames.CODE)) {
|
|
||||||
additionalParameters.put(key, value.get(0));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//返回自定义的PasswordGrantAuthenticationToken对象
|
|
||||||
return new PasswordGrantAuthenticationToken(clientPrincipal, additionalParameters);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*从request中提取请求参数,然后存入MultiValueMap<String, String>
|
|
||||||
*/
|
|
||||||
private static MultiValueMap<String, String> getParameters(HttpServletRequest request) {
|
|
||||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
|
||||||
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>(parameterMap.size());
|
|
||||||
parameterMap.forEach((key, values) -> {
|
|
||||||
if (values.length > 0) {
|
|
||||||
for (String value : values) {
|
|
||||||
parameters.add(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return parameters;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,320 +0,0 @@
|
|||||||
package org.jeecg.config.security.app;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.jeecg.common.api.CommonAPI;
|
|
||||||
import org.jeecg.common.constant.CacheConstant;
|
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
|
||||||
import org.jeecg.common.exception.JeecgBootException;
|
|
||||||
import org.jeecg.common.exception.JeecgCaptchaException;
|
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
|
||||||
import org.jeecg.common.system.vo.SysDepartModel;
|
|
||||||
import org.jeecg.common.util.Md5Util;
|
|
||||||
import org.jeecg.common.util.PasswordUtil;
|
|
||||||
import org.jeecg.common.util.RedisUtil;
|
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
|
||||||
import org.jeecg.config.JeecgBaseConfig;
|
|
||||||
import org.jeecg.config.security.password.PasswordGrantAuthenticationToken;
|
|
||||||
import org.jeecg.modules.base.service.BaseCommonService;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Lazy;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.security.oauth2.core.*;
|
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.context.AuthorizationServerContextHolder;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import java.security.Principal;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* APP模式认证处理器,负责处理该认证模式下的核心逻辑
|
|
||||||
* @author EightMonth
|
|
||||||
* @date 2024/1/1
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
public class AppGrantAuthenticationProvider implements AuthenticationProvider {
|
|
||||||
|
|
||||||
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
|
|
||||||
|
|
||||||
private final OAuth2AuthorizationService authorizationService;
|
|
||||||
private final OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator;
|
|
||||||
@Lazy
|
|
||||||
@Autowired
|
|
||||||
private CommonAPI commonAPI;
|
|
||||||
@Autowired
|
|
||||||
private RedisUtil redisUtil;
|
|
||||||
@Autowired
|
|
||||||
private JeecgBaseConfig jeecgBaseConfig;
|
|
||||||
@Autowired
|
|
||||||
private BaseCommonService baseCommonService;
|
|
||||||
|
|
||||||
public AppGrantAuthenticationProvider(OAuth2AuthorizationService authorizationService, OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator) {
|
|
||||||
Assert.notNull(authorizationService, "authorizationService cannot be null");
|
|
||||||
Assert.notNull(tokenGenerator, "tokenGenerator cannot be null");
|
|
||||||
this.authorizationService = authorizationService;
|
|
||||||
this.tokenGenerator = tokenGenerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
|
||||||
AppGrantAuthenticationToken appGrantAuthenticationToken = (AppGrantAuthenticationToken) authentication;
|
|
||||||
Map<String, Object> additionalParameter = appGrantAuthenticationToken.getAdditionalParameters();
|
|
||||||
|
|
||||||
// 授权类型
|
|
||||||
AuthorizationGrantType authorizationGrantType = appGrantAuthenticationToken.getGrantType();
|
|
||||||
// 用户名
|
|
||||||
String username = (String) additionalParameter.get(OAuth2ParameterNames.USERNAME);
|
|
||||||
// 密码
|
|
||||||
String password = (String) additionalParameter.get(OAuth2ParameterNames.PASSWORD);
|
|
||||||
//请求参数权限范围
|
|
||||||
String requestScopesStr = (String)additionalParameter.getOrDefault(OAuth2ParameterNames.SCOPE, "*");
|
|
||||||
//请求参数权限范围专场集合
|
|
||||||
Set<String> requestScopeSet = Stream.of(requestScopesStr.split(" ")).collect(Collectors.toSet());
|
|
||||||
// 验证码
|
|
||||||
String captcha = (String) additionalParameter.get("captcha");
|
|
||||||
String checkKey = (String) additionalParameter.get("checkKey");
|
|
||||||
|
|
||||||
OAuth2ClientAuthenticationToken clientPrincipal = getAuthenticatedClientElseThrowInvalidClient(appGrantAuthenticationToken);
|
|
||||||
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();
|
|
||||||
|
|
||||||
// 检查登录失败次数
|
|
||||||
if(isLoginFailOvertimes(username)){
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("message", "该用户登录失败次数过多,请于10分钟后再次登录!");
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(captcha==null){
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("message", "验证码无效");
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
|
|
||||||
}
|
|
||||||
String lowerCaseCaptcha = captcha.toLowerCase();
|
|
||||||
// 加入密钥作为混淆,避免简单的拼接,被外部利用,用户自定义该密钥即可
|
|
||||||
String origin = lowerCaseCaptcha+checkKey+jeecgBaseConfig.getSignatureSecret();
|
|
||||||
String realKey = Md5Util.md5Encode(origin, "utf-8");
|
|
||||||
Object checkCode = redisUtil.get(realKey);
|
|
||||||
//当进入登录页时,有一定几率出现验证码错误 #1714
|
|
||||||
if(checkCode==null || !checkCode.toString().equals(lowerCaseCaptcha)) {
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("message", "验证码错误");
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!registeredClient.getAuthorizationGrantTypes().contains(authorizationGrantType)) {
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("message", "非法登录");
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 通过用户名获取用户信息
|
|
||||||
LoginUser loginUser = commonAPI.getUserByName(username);
|
|
||||||
//update-begin---author:eightmonth ---date:2024-04-30 for:【6168】master分支切sas分支登录发生错误-----------
|
|
||||||
if (Objects.isNull(loginUser) || !StringUtils.hasText(loginUser.getSalt())) {
|
|
||||||
redisUtil.del(CacheConstant.SYS_USERS_CACHE+"::"+username);
|
|
||||||
loginUser = commonAPI.getUserByName(username);
|
|
||||||
}
|
|
||||||
//update-end---author:eightmonth ---date::2024-04-30 for:【6168】master分支切sas分支登录发生错误--------------
|
|
||||||
// 检查用户可行性
|
|
||||||
checkUserIsEffective(loginUser);
|
|
||||||
|
|
||||||
// 不使用spring security passwordEncoder针对密码进行匹配,使用自有加密匹配,针对 spring security使用noop传输
|
|
||||||
password = PasswordUtil.encrypt(username, password, loginUser.getSalt());
|
|
||||||
if (!password.equals(loginUser.getPassword())) {
|
|
||||||
addLoginFailOvertimes(username);
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("message", "用户名或密码不正确");
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
//由于在上面已验证过用户名、密码,现在构建一个已认证的对象UsernamePasswordAuthenticationToken
|
|
||||||
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = UsernamePasswordAuthenticationToken.authenticated(loginUser,clientPrincipal,new ArrayList<>());
|
|
||||||
|
|
||||||
DefaultOAuth2TokenContext.Builder tokenContextBuilder = DefaultOAuth2TokenContext.builder()
|
|
||||||
.registeredClient(registeredClient)
|
|
||||||
.principal(usernamePasswordAuthenticationToken)
|
|
||||||
.authorizationServerContext(AuthorizationServerContextHolder.getContext())
|
|
||||||
.authorizationGrantType(authorizationGrantType)
|
|
||||||
.authorizedScopes(requestScopeSet)
|
|
||||||
.authorizationGrant(appGrantAuthenticationToken);
|
|
||||||
|
|
||||||
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient)
|
|
||||||
.principalName(clientPrincipal.getName())
|
|
||||||
.authorizedScopes(requestScopeSet)
|
|
||||||
.attribute(Principal.class.getName(), username)
|
|
||||||
.authorizationGrantType(authorizationGrantType);
|
|
||||||
|
|
||||||
|
|
||||||
// ----- Access token -----
|
|
||||||
OAuth2TokenContext tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.ACCESS_TOKEN).build();
|
|
||||||
OAuth2Token generatedAccessToken = this.tokenGenerator.generate(tokenContext);
|
|
||||||
if (generatedAccessToken == null) {
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("message", "无法生成访问token,请联系管理系。");
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
|
|
||||||
}
|
|
||||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
|
|
||||||
generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),
|
|
||||||
generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
|
|
||||||
if (generatedAccessToken instanceof ClaimAccessor) {
|
|
||||||
authorizationBuilder.token(accessToken, (metadata) -> {
|
|
||||||
metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME, ((ClaimAccessor) generatedAccessToken).getClaims());
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
authorizationBuilder.accessToken(accessToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----- Refresh token -----
|
|
||||||
OAuth2RefreshToken refreshToken = null;
|
|
||||||
if (registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.REFRESH_TOKEN) &&
|
|
||||||
// 不向公共客户端颁发刷新令牌
|
|
||||||
!clientPrincipal.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.NONE)) {
|
|
||||||
|
|
||||||
tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.REFRESH_TOKEN).build();
|
|
||||||
OAuth2Token generatedRefreshToken = this.tokenGenerator.generate(tokenContext);
|
|
||||||
if (!(generatedRefreshToken instanceof OAuth2RefreshToken)) {
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("message", "无法生成刷新token,请联系管理员。");
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
refreshToken = (OAuth2RefreshToken) generatedRefreshToken;
|
|
||||||
authorizationBuilder.refreshToken(refreshToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
OAuth2Authorization authorization = authorizationBuilder.build();
|
|
||||||
|
|
||||||
// 保存认证信息至redis
|
|
||||||
authorizationService.save(authorization);
|
|
||||||
|
|
||||||
// 登录成功,删除redis中的验证码
|
|
||||||
redisUtil.del(realKey);
|
|
||||||
redisUtil.del(CommonConstant.LOGIN_FAIL + username);
|
|
||||||
baseCommonService.addLog("用户名: " + username + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser);
|
|
||||||
|
|
||||||
JSONObject addition = new JSONObject(new LinkedHashMap<>());
|
|
||||||
addition.put("token", accessToken.getTokenValue());
|
|
||||||
// 设置租户
|
|
||||||
JSONObject jsonObject = commonAPI.setLoginTenant(username);
|
|
||||||
addition.putAll(jsonObject.getInnerMap());
|
|
||||||
|
|
||||||
// 设置登录用户信息
|
|
||||||
addition.put("userInfo", loginUser);
|
|
||||||
addition.put("sysAllDictItems", commonAPI.queryAllDictItems());
|
|
||||||
|
|
||||||
List<SysDepartModel> departs = commonAPI.queryUserDeparts(loginUser.getId());
|
|
||||||
addition.put("departs", departs);
|
|
||||||
if (departs == null || departs.size() == 0) {
|
|
||||||
addition.put("multi_depart", 0);
|
|
||||||
} else if (departs.size() == 1) {
|
|
||||||
commonAPI.updateUserDepart(username, departs.get(0).getOrgCode(),null);
|
|
||||||
addition.put("multi_depart", 1);
|
|
||||||
} else {
|
|
||||||
//查询当前是否有登录部门
|
|
||||||
if(oConvertUtils.isEmpty(loginUser.getOrgCode())){
|
|
||||||
commonAPI.updateUserDepart(username, departs.get(0).getOrgCode(),null);
|
|
||||||
}
|
|
||||||
addition.put("multi_depart", 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 兼容原有shiro登录结果处理
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("result", addition);
|
|
||||||
map.put("code", 200);
|
|
||||||
map.put("success", true);
|
|
||||||
map.put("timestamp", System.currentTimeMillis());
|
|
||||||
|
|
||||||
// 返回access_token、refresh_token以及其它信息给到前端
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> authentication) {
|
|
||||||
return AppGrantAuthenticationToken.class.isAssignableFrom(authentication);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static OAuth2ClientAuthenticationToken getAuthenticatedClientElseThrowInvalidClient(Authentication authentication) {
|
|
||||||
OAuth2ClientAuthenticationToken clientPrincipal = null;
|
|
||||||
if (OAuth2ClientAuthenticationToken.class.isAssignableFrom(authentication.getPrincipal().getClass())) {
|
|
||||||
clientPrincipal = (OAuth2ClientAuthenticationToken) authentication.getPrincipal();
|
|
||||||
}
|
|
||||||
if (clientPrincipal != null && clientPrincipal.isAuthenticated()) {
|
|
||||||
return clientPrincipal;
|
|
||||||
}
|
|
||||||
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_CLIENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录失败超出次数5 返回true
|
|
||||||
* @param username
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private boolean isLoginFailOvertimes(String username){
|
|
||||||
String key = CommonConstant.LOGIN_FAIL + username;
|
|
||||||
Object failTime = redisUtil.get(key);
|
|
||||||
if(failTime!=null){
|
|
||||||
Integer val = Integer.parseInt(failTime.toString());
|
|
||||||
if(val>5){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 记录登录失败次数
|
|
||||||
* @param username
|
|
||||||
*/
|
|
||||||
private void addLoginFailOvertimes(String username){
|
|
||||||
String key = CommonConstant.LOGIN_FAIL + username;
|
|
||||||
Object failTime = redisUtil.get(key);
|
|
||||||
Integer val = 0;
|
|
||||||
if(failTime!=null){
|
|
||||||
val = Integer.parseInt(failTime.toString());
|
|
||||||
}
|
|
||||||
// 10分钟
|
|
||||||
redisUtil.set(key, ++val, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验用户是否有效
|
|
||||||
*/
|
|
||||||
private void checkUserIsEffective(LoginUser loginUser) {
|
|
||||||
//情况1:根据用户信息查询,该用户不存在
|
|
||||||
if (Objects.isNull(loginUser)) {
|
|
||||||
baseCommonService.addLog("用户登录失败,用户不存在!", CommonConstant.LOG_TYPE_1, null);
|
|
||||||
throw new JeecgBootException("该用户不存在,请注册");
|
|
||||||
}
|
|
||||||
//情况2:根据用户信息查询,该用户已注销
|
|
||||||
//update-begin---author:王帅 Date:20200601 for:if条件永远为falsebug------------
|
|
||||||
if (CommonConstant.DEL_FLAG_1.equals(loginUser.getDelFlag())) {
|
|
||||||
//update-end---author:王帅 Date:20200601 for:if条件永远为falsebug------------
|
|
||||||
baseCommonService.addLog("用户登录失败,用户名:" + loginUser.getUsername() + "已注销!", CommonConstant.LOG_TYPE_1, null);
|
|
||||||
throw new JeecgBootException("该用户已注销");
|
|
||||||
}
|
|
||||||
//情况3:根据用户信息查询,该用户已冻结
|
|
||||||
if (CommonConstant.USER_FREEZE.equals(loginUser.getStatus())) {
|
|
||||||
baseCommonService.addLog("用户登录失败,用户名:" + loginUser.getUsername() + "已冻结!", CommonConstant.LOG_TYPE_1, null);
|
|
||||||
throw new JeecgBootException("该用户已冻结");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
package org.jeecg.config.security.app;
|
|
||||||
|
|
||||||
import org.jeecg.config.security.LoginType;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* APP模式认证专用token类型,方法spring authorization server进行认证流转,配合convert使用
|
|
||||||
* @author EightMonth
|
|
||||||
* @date 2024/1/1
|
|
||||||
*/
|
|
||||||
public class AppGrantAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken {
|
|
||||||
|
|
||||||
public AppGrantAuthenticationToken(Authentication clientPrincipal, Map<String, Object> additionalParameters) {
|
|
||||||
super(new AuthorizationGrantType(LoginType.APP), clientPrincipal, additionalParameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,82 +0,0 @@
|
|||||||
package org.jeecg.config.security.password;
|
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
|
||||||
import org.jeecg.config.security.LoginType;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
|
||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
|
||||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
|
||||||
import org.springframework.util.MultiValueMap;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 密码模式认证转换器
|
|
||||||
* @author EightMonth
|
|
||||||
* @date 2024/1/1
|
|
||||||
*/
|
|
||||||
public class PasswordGrantAuthenticationConvert implements AuthenticationConverter {
|
|
||||||
@Override
|
|
||||||
public Authentication convert(HttpServletRequest request) {
|
|
||||||
|
|
||||||
String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
|
|
||||||
if (!LoginType.PASSWORD.equals(grantType)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();
|
|
||||||
|
|
||||||
//从request中提取请求参数,然后存入MultiValueMap<String, String>
|
|
||||||
MultiValueMap<String, String> parameters = getParameters(request);
|
|
||||||
|
|
||||||
// username (REQUIRED)
|
|
||||||
String username = parameters.getFirst(OAuth2ParameterNames.USERNAME);
|
|
||||||
if (!StringUtils.hasText(username) ||
|
|
||||||
parameters.get(OAuth2ParameterNames.USERNAME).size() != 1) {
|
|
||||||
throw new OAuth2AuthenticationException("无效请求,用户名不能为空!");
|
|
||||||
}
|
|
||||||
String password = parameters.getFirst(OAuth2ParameterNames.PASSWORD);
|
|
||||||
if (!StringUtils.hasText(password) ||
|
|
||||||
parameters.get(OAuth2ParameterNames.PASSWORD).size() != 1) {
|
|
||||||
throw new OAuth2AuthenticationException("无效请求,密码不能为空!");
|
|
||||||
}
|
|
||||||
|
|
||||||
//收集要传入PasswordGrantAuthenticationToken构造方法的参数,
|
|
||||||
//该参数接下来在PasswordGrantAuthenticationProvider中使用
|
|
||||||
Map<String, Object> additionalParameters = new HashMap<>();
|
|
||||||
//遍历从request中提取的参数,排除掉grant_type、client_id、code等字段参数,其他参数收集到additionalParameters中
|
|
||||||
parameters.forEach((key, value) -> {
|
|
||||||
if (!key.equals(OAuth2ParameterNames.GRANT_TYPE) &&
|
|
||||||
!key.equals(OAuth2ParameterNames.CLIENT_ID) &&
|
|
||||||
!key.equals(OAuth2ParameterNames.CODE)) {
|
|
||||||
additionalParameters.put(key, value.get(0));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//返回自定义的PasswordGrantAuthenticationToken对象
|
|
||||||
return new PasswordGrantAuthenticationToken(clientPrincipal, additionalParameters);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*从request中提取请求参数,然后存入MultiValueMap<String, String>
|
|
||||||
*/
|
|
||||||
private static MultiValueMap<String, String> getParameters(HttpServletRequest request) {
|
|
||||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
|
||||||
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>(parameterMap.size());
|
|
||||||
parameterMap.forEach((key, values) -> {
|
|
||||||
if (values.length > 0) {
|
|
||||||
for (String value : values) {
|
|
||||||
parameters.add(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return parameters;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,319 +0,0 @@
|
|||||||
package org.jeecg.config.security.password;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.jeecg.common.api.CommonAPI;
|
|
||||||
import org.jeecg.common.constant.CacheConstant;
|
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
|
||||||
import org.jeecg.common.exception.JeecgBootException;
|
|
||||||
import org.jeecg.common.exception.JeecgCaptchaException;
|
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
|
||||||
import org.jeecg.common.system.vo.SysDepartModel;
|
|
||||||
import org.jeecg.common.util.Md5Util;
|
|
||||||
import org.jeecg.common.util.PasswordUtil;
|
|
||||||
import org.jeecg.common.util.RedisUtil;
|
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
|
||||||
import org.jeecg.config.JeecgBaseConfig;
|
|
||||||
import org.jeecg.modules.base.service.BaseCommonService;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Lazy;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
|
||||||
import org.springframework.security.oauth2.core.*;
|
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.context.AuthorizationServerContextHolder;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import java.security.Principal;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 密码模式认证处理器,负责处理该认证模式下的核心逻辑
|
|
||||||
* @author EightMonth
|
|
||||||
* @date 2024/1/1
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
public class PasswordGrantAuthenticationProvider implements AuthenticationProvider {
|
|
||||||
|
|
||||||
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
|
|
||||||
|
|
||||||
private final OAuth2AuthorizationService authorizationService;
|
|
||||||
private final OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator;
|
|
||||||
@Lazy
|
|
||||||
@Autowired
|
|
||||||
private CommonAPI commonAPI;
|
|
||||||
@Autowired
|
|
||||||
private RedisUtil redisUtil;
|
|
||||||
@Autowired
|
|
||||||
private JeecgBaseConfig jeecgBaseConfig;
|
|
||||||
@Autowired
|
|
||||||
private BaseCommonService baseCommonService;
|
|
||||||
|
|
||||||
public PasswordGrantAuthenticationProvider(OAuth2AuthorizationService authorizationService, OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator) {
|
|
||||||
Assert.notNull(authorizationService, "authorizationService cannot be null");
|
|
||||||
Assert.notNull(tokenGenerator, "tokenGenerator cannot be null");
|
|
||||||
this.authorizationService = authorizationService;
|
|
||||||
this.tokenGenerator = tokenGenerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
|
||||||
PasswordGrantAuthenticationToken passwordGrantAuthenticationToken = (PasswordGrantAuthenticationToken) authentication;
|
|
||||||
Map<String, Object> additionalParameter = passwordGrantAuthenticationToken.getAdditionalParameters();
|
|
||||||
|
|
||||||
// 授权类型
|
|
||||||
AuthorizationGrantType authorizationGrantType = passwordGrantAuthenticationToken.getGrantType();
|
|
||||||
// 用户名
|
|
||||||
String username = (String) additionalParameter.get(OAuth2ParameterNames.USERNAME);
|
|
||||||
// 密码
|
|
||||||
String password = (String) additionalParameter.get(OAuth2ParameterNames.PASSWORD);
|
|
||||||
//请求参数权限范围
|
|
||||||
String requestScopesStr = (String)additionalParameter.getOrDefault(OAuth2ParameterNames.SCOPE, "*");
|
|
||||||
//请求参数权限范围专场集合
|
|
||||||
Set<String> requestScopeSet = Stream.of(requestScopesStr.split(" ")).collect(Collectors.toSet());
|
|
||||||
// 验证码
|
|
||||||
String captcha = (String) additionalParameter.get("captcha");
|
|
||||||
String checkKey = (String) additionalParameter.get("checkKey");
|
|
||||||
|
|
||||||
OAuth2ClientAuthenticationToken clientPrincipal = getAuthenticatedClientElseThrowInvalidClient(passwordGrantAuthenticationToken);
|
|
||||||
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();
|
|
||||||
|
|
||||||
// 检查登录失败次数
|
|
||||||
if(isLoginFailOvertimes(username)){
|
|
||||||
throw new JeecgBootException("该用户登录失败次数过多,请于10分钟后再次登录!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(captcha==null){
|
|
||||||
throw new JeecgBootException("验证码无效");
|
|
||||||
}
|
|
||||||
String lowerCaseCaptcha = captcha.toLowerCase();
|
|
||||||
// 加入密钥作为混淆,避免简单的拼接,被外部利用,用户自定义该密钥即可
|
|
||||||
String origin = lowerCaseCaptcha+checkKey+jeecgBaseConfig.getSignatureSecret();
|
|
||||||
String realKey = Md5Util.md5Encode(origin, "utf-8");
|
|
||||||
Object checkCode = redisUtil.get(realKey);
|
|
||||||
//当进入登录页时,有一定几率出现验证码错误 #1714
|
|
||||||
if(checkCode==null || !checkCode.toString().equals(lowerCaseCaptcha)) {
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("message", "验证码错误");
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!registeredClient.getAuthorizationGrantTypes().contains(authorizationGrantType)) {
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("message", "非法登录");
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 通过用户名获取用户信息
|
|
||||||
LoginUser loginUser = commonAPI.getUserByName(username);
|
|
||||||
//update-begin---author:eightmonth ---date:2024-04-30 for:【6168】master分支切sas分支登录发生错误-----------
|
|
||||||
if (Objects.isNull(loginUser) || !StringUtils.hasText(loginUser.getSalt())) {
|
|
||||||
redisUtil.del(CacheConstant.SYS_USERS_CACHE+"::"+username);
|
|
||||||
loginUser = commonAPI.getUserByName(username);
|
|
||||||
}
|
|
||||||
//update-end---author:eightmonth ---date::2024-04-30 for:【6168】master分支切sas分支登录发生错误--------------
|
|
||||||
// 检查用户可行性
|
|
||||||
checkUserIsEffective(loginUser);
|
|
||||||
|
|
||||||
// 不使用spring security passwordEncoder针对密码进行匹配,使用自有加密匹配,针对 spring security使用noop传输
|
|
||||||
password = PasswordUtil.encrypt(username, password, loginUser.getSalt());
|
|
||||||
if (!password.equals(loginUser.getPassword())) {
|
|
||||||
addLoginFailOvertimes(username);
|
|
||||||
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("message", "用户名或密码不正确");
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
//由于在上面已验证过用户名、密码,现在构建一个已认证的对象UsernamePasswordAuthenticationToken
|
|
||||||
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = UsernamePasswordAuthenticationToken.authenticated(loginUser,clientPrincipal,new ArrayList<>());
|
|
||||||
|
|
||||||
DefaultOAuth2TokenContext.Builder tokenContextBuilder = DefaultOAuth2TokenContext.builder()
|
|
||||||
.registeredClient(registeredClient)
|
|
||||||
.principal(usernamePasswordAuthenticationToken)
|
|
||||||
.authorizationServerContext(AuthorizationServerContextHolder.getContext())
|
|
||||||
.authorizationGrantType(authorizationGrantType)
|
|
||||||
.authorizedScopes(requestScopeSet)
|
|
||||||
.authorizationGrant(passwordGrantAuthenticationToken);
|
|
||||||
|
|
||||||
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient)
|
|
||||||
.principalName(clientPrincipal.getName())
|
|
||||||
.authorizedScopes(requestScopeSet)
|
|
||||||
.attribute(Principal.class.getName(), username)
|
|
||||||
.authorizationGrantType(authorizationGrantType);
|
|
||||||
|
|
||||||
|
|
||||||
// ----- Access token -----
|
|
||||||
OAuth2TokenContext tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.ACCESS_TOKEN).build();
|
|
||||||
OAuth2Token generatedAccessToken = this.tokenGenerator.generate(tokenContext);
|
|
||||||
if (generatedAccessToken == null) {
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("message", "无法生成访问token,请联系管理系。");
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
|
|
||||||
}
|
|
||||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
|
|
||||||
generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),
|
|
||||||
generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
|
|
||||||
if (generatedAccessToken instanceof ClaimAccessor) {
|
|
||||||
authorizationBuilder.token(accessToken, (metadata) -> {
|
|
||||||
metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME, ((ClaimAccessor) generatedAccessToken).getClaims());
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
authorizationBuilder.accessToken(accessToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----- Refresh token -----
|
|
||||||
OAuth2RefreshToken refreshToken = null;
|
|
||||||
if (registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.REFRESH_TOKEN) &&
|
|
||||||
// 不向公共客户端颁发刷新令牌
|
|
||||||
!clientPrincipal.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.NONE)) {
|
|
||||||
|
|
||||||
tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.REFRESH_TOKEN).build();
|
|
||||||
OAuth2Token generatedRefreshToken = this.tokenGenerator.generate(tokenContext);
|
|
||||||
if (!(generatedRefreshToken instanceof OAuth2RefreshToken)) {
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("message", "无法生成访问token,请联系管理系。");
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
refreshToken = (OAuth2RefreshToken) generatedRefreshToken;
|
|
||||||
authorizationBuilder.refreshToken(refreshToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
OAuth2Authorization authorization = authorizationBuilder.build();
|
|
||||||
|
|
||||||
// 保存认证信息至redis
|
|
||||||
authorizationService.save(authorization);
|
|
||||||
|
|
||||||
// 登录成功,删除redis中的验证码
|
|
||||||
redisUtil.del(realKey);
|
|
||||||
redisUtil.del(CommonConstant.LOGIN_FAIL + username);
|
|
||||||
baseCommonService.addLog("用户名: " + username + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser);
|
|
||||||
|
|
||||||
JSONObject addition = new JSONObject(new LinkedHashMap<>());
|
|
||||||
addition.put("token", accessToken.getTokenValue());
|
|
||||||
|
|
||||||
// 设置租户
|
|
||||||
JSONObject jsonObject = commonAPI.setLoginTenant(username);
|
|
||||||
addition.putAll(jsonObject.getInnerMap());
|
|
||||||
|
|
||||||
// 设置登录用户信息
|
|
||||||
addition.put("userInfo", loginUser);
|
|
||||||
addition.put("sysAllDictItems", commonAPI.queryAllDictItems());
|
|
||||||
|
|
||||||
List<SysDepartModel> departs = commonAPI.queryUserDeparts(loginUser.getId());
|
|
||||||
addition.put("departs", departs);
|
|
||||||
if (departs == null || departs.size() == 0) {
|
|
||||||
addition.put("multi_depart", 0);
|
|
||||||
} else if (departs.size() == 1) {
|
|
||||||
commonAPI.updateUserDepart(username, departs.get(0).getOrgCode(),null);
|
|
||||||
addition.put("multi_depart", 1);
|
|
||||||
} else {
|
|
||||||
//查询当前是否有登录部门
|
|
||||||
if(oConvertUtils.isEmpty(loginUser.getOrgCode())){
|
|
||||||
commonAPI.updateUserDepart(username, departs.get(0).getOrgCode(),null);
|
|
||||||
}
|
|
||||||
addition.put("multi_depart", 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 兼容原有shiro登录结果处理
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("result", addition);
|
|
||||||
map.put("code", 200);
|
|
||||||
map.put("success", true);
|
|
||||||
map.put("timestamp", System.currentTimeMillis());
|
|
||||||
|
|
||||||
// 返回access_token、refresh_token以及其它信息给到前端
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> authentication) {
|
|
||||||
return PasswordGrantAuthenticationToken.class.isAssignableFrom(authentication);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static OAuth2ClientAuthenticationToken getAuthenticatedClientElseThrowInvalidClient(Authentication authentication) {
|
|
||||||
OAuth2ClientAuthenticationToken clientPrincipal = null;
|
|
||||||
if (OAuth2ClientAuthenticationToken.class.isAssignableFrom(authentication.getPrincipal().getClass())) {
|
|
||||||
clientPrincipal = (OAuth2ClientAuthenticationToken) authentication.getPrincipal();
|
|
||||||
}
|
|
||||||
if (clientPrincipal != null && clientPrincipal.isAuthenticated()) {
|
|
||||||
return clientPrincipal;
|
|
||||||
}
|
|
||||||
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_CLIENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录失败超出次数5 返回true
|
|
||||||
* @param username
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private boolean isLoginFailOvertimes(String username){
|
|
||||||
String key = CommonConstant.LOGIN_FAIL + username;
|
|
||||||
Object failTime = redisUtil.get(key);
|
|
||||||
if(failTime!=null){
|
|
||||||
Integer val = Integer.parseInt(failTime.toString());
|
|
||||||
if(val>5){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 记录登录失败次数
|
|
||||||
* @param username
|
|
||||||
*/
|
|
||||||
private void addLoginFailOvertimes(String username){
|
|
||||||
String key = CommonConstant.LOGIN_FAIL + username;
|
|
||||||
Object failTime = redisUtil.get(key);
|
|
||||||
Integer val = 0;
|
|
||||||
if(failTime!=null){
|
|
||||||
val = Integer.parseInt(failTime.toString());
|
|
||||||
}
|
|
||||||
// 10分钟
|
|
||||||
redisUtil.set(key, ++val, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验用户是否有效
|
|
||||||
*/
|
|
||||||
private void checkUserIsEffective(LoginUser loginUser) {
|
|
||||||
//情况1:根据用户信息查询,该用户不存在
|
|
||||||
if (Objects.isNull(loginUser)) {
|
|
||||||
baseCommonService.addLog("用户登录失败,用户不存在!", CommonConstant.LOG_TYPE_1, null);
|
|
||||||
throw new JeecgBootException("该用户不存在,请注册");
|
|
||||||
}
|
|
||||||
//情况2:根据用户信息查询,该用户已注销
|
|
||||||
//update-begin---author:王帅 Date:20200601 for:if条件永远为falsebug------------
|
|
||||||
if (CommonConstant.DEL_FLAG_1.equals(loginUser.getDelFlag())) {
|
|
||||||
//update-end---author:王帅 Date:20200601 for:if条件永远为falsebug------------
|
|
||||||
baseCommonService.addLog("用户登录失败,用户名:" + loginUser.getUsername() + "已注销!", CommonConstant.LOG_TYPE_1, null);
|
|
||||||
throw new JeecgBootException("该用户已注销");
|
|
||||||
}
|
|
||||||
//情况3:根据用户信息查询,该用户已冻结
|
|
||||||
if (CommonConstant.USER_FREEZE.equals(loginUser.getStatus())) {
|
|
||||||
baseCommonService.addLog("用户登录失败,用户名:" + loginUser.getUsername() + "已冻结!", CommonConstant.LOG_TYPE_1, null);
|
|
||||||
throw new JeecgBootException("该用户已冻结");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
package org.jeecg.config.security.password;
|
|
||||||
|
|
||||||
import org.jeecg.config.security.LoginType;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 密码模式认证专用token类型,方法spring authorization server进行认证流转,配合convert使用
|
|
||||||
* @author EightMonth
|
|
||||||
* @date 2024/1/1
|
|
||||||
*/
|
|
||||||
public class PasswordGrantAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken {
|
|
||||||
|
|
||||||
public PasswordGrantAuthenticationToken(Authentication clientPrincipal, Map<String, Object> additionalParameters) {
|
|
||||||
super(new AuthorizationGrantType(LoginType.PASSWORD), clientPrincipal, additionalParameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,77 +0,0 @@
|
|||||||
package org.jeecg.config.security.phone;
|
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import org.jeecg.config.security.LoginType;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
|
||||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
|
||||||
import org.springframework.util.MultiValueMap;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 手机号模式认证转换器
|
|
||||||
* @author EightMonth
|
|
||||||
* @date 2024/1/1
|
|
||||||
*/
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class PhoneGrantAuthenticationConvert implements AuthenticationConverter {
|
|
||||||
@Override
|
|
||||||
public Authentication convert(HttpServletRequest request) {
|
|
||||||
|
|
||||||
String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
|
|
||||||
if (!LoginType.PHONE.equals(grantType)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();
|
|
||||||
|
|
||||||
//从request中提取请求参数,然后存入MultiValueMap<String, String>
|
|
||||||
MultiValueMap<String, String> parameters = getParameters(request);
|
|
||||||
|
|
||||||
// 验证码
|
|
||||||
String captcha = parameters.getFirst("captcha");
|
|
||||||
if (!StringUtils.hasText(captcha)) {
|
|
||||||
throw new OAuth2AuthenticationException("无效请求,验证码不能为空!");
|
|
||||||
}
|
|
||||||
|
|
||||||
//收集要传入PhoneGrantAuthenticationToken构造方法的参数,
|
|
||||||
//该参数接下来在PhoneGrantAuthenticationProvider中使用
|
|
||||||
Map<String, Object> additionalParameters = new HashMap<>();
|
|
||||||
//遍历从request中提取的参数,排除掉grant_type、client_id、code等字段参数,其他参数收集到additionalParameters中
|
|
||||||
parameters.forEach((key, value) -> {
|
|
||||||
if (!key.equals(OAuth2ParameterNames.GRANT_TYPE) &&
|
|
||||||
!key.equals(OAuth2ParameterNames.CLIENT_ID) &&
|
|
||||||
!key.equals(OAuth2ParameterNames.CODE)) {
|
|
||||||
additionalParameters.put(key, value.get(0));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//返回自定义的PhoneGrantAuthenticationToken对象
|
|
||||||
return new PhoneGrantAuthenticationToken(clientPrincipal, additionalParameters);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*从request中提取请求参数,然后存入MultiValueMap<String, String>
|
|
||||||
*/
|
|
||||||
private static MultiValueMap<String, String> getParameters(HttpServletRequest request) {
|
|
||||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
|
||||||
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>(parameterMap.size());
|
|
||||||
parameterMap.forEach((key, values) -> {
|
|
||||||
if (values.length > 0) {
|
|
||||||
for (String value : values) {
|
|
||||||
parameters.add(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,292 +0,0 @@
|
|||||||
package org.jeecg.config.security.phone;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.jeecg.common.api.CommonAPI;
|
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
|
||||||
import org.jeecg.common.exception.JeecgBootException;
|
|
||||||
import org.jeecg.common.exception.JeecgCaptchaException;
|
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
|
||||||
import org.jeecg.common.system.vo.SysDepartModel;
|
|
||||||
import org.jeecg.common.util.Md5Util;
|
|
||||||
import org.jeecg.common.util.PasswordUtil;
|
|
||||||
import org.jeecg.common.util.RedisUtil;
|
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
|
||||||
import org.jeecg.config.JeecgBaseConfig;
|
|
||||||
import org.jeecg.config.security.password.PasswordGrantAuthenticationToken;
|
|
||||||
import org.jeecg.modules.base.service.BaseCommonService;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Lazy;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.security.oauth2.core.*;
|
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.context.AuthorizationServerContextHolder;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
import java.security.Principal;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 手机号模式认证处理器,负责处理该认证模式下的核心逻辑
|
|
||||||
* @author EightMonth
|
|
||||||
* @date 2024/1/1
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
public class PhoneGrantAuthenticationProvider implements AuthenticationProvider {
|
|
||||||
|
|
||||||
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
|
|
||||||
|
|
||||||
private final OAuth2AuthorizationService authorizationService;
|
|
||||||
private final OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator;
|
|
||||||
@Lazy
|
|
||||||
@Autowired
|
|
||||||
private CommonAPI commonAPI;
|
|
||||||
@Autowired
|
|
||||||
private RedisUtil redisUtil;
|
|
||||||
@Autowired
|
|
||||||
private JeecgBaseConfig jeecgBaseConfig;
|
|
||||||
@Autowired
|
|
||||||
private BaseCommonService baseCommonService;
|
|
||||||
|
|
||||||
public PhoneGrantAuthenticationProvider(OAuth2AuthorizationService authorizationService, OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator) {
|
|
||||||
Assert.notNull(authorizationService, "authorizationService cannot be null");
|
|
||||||
Assert.notNull(tokenGenerator, "tokenGenerator cannot be null");
|
|
||||||
this.authorizationService = authorizationService;
|
|
||||||
this.tokenGenerator = tokenGenerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
|
||||||
PhoneGrantAuthenticationToken phoneGrantAuthenticationToken = (PhoneGrantAuthenticationToken) authentication;
|
|
||||||
Map<String, Object> additionalParameter = phoneGrantAuthenticationToken.getAdditionalParameters();
|
|
||||||
|
|
||||||
// 授权类型
|
|
||||||
AuthorizationGrantType authorizationGrantType = phoneGrantAuthenticationToken.getGrantType();
|
|
||||||
// 手机号
|
|
||||||
String phone = (String) additionalParameter.get("mobile");
|
|
||||||
|
|
||||||
if(isLoginFailOvertimes(phone)){
|
|
||||||
throw new JeecgBootException("该用户登录失败次数过多,请于10分钟后再次登录!");
|
|
||||||
}
|
|
||||||
|
|
||||||
//请求参数权限范围
|
|
||||||
String requestScopesStr = (String)additionalParameter.getOrDefault(OAuth2ParameterNames.SCOPE, "*");
|
|
||||||
//请求参数权限范围专场集合
|
|
||||||
Set<String> requestScopeSet = Stream.of(requestScopesStr.split(" ")).collect(Collectors.toSet());
|
|
||||||
// 验证码
|
|
||||||
String captcha = (String) additionalParameter.get("captcha");
|
|
||||||
|
|
||||||
OAuth2ClientAuthenticationToken clientPrincipal = getAuthenticatedClientElseThrowInvalidClient(phoneGrantAuthenticationToken);
|
|
||||||
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();
|
|
||||||
|
|
||||||
// 通过手机号获取用户信息
|
|
||||||
LoginUser loginUser = commonAPI.getUserByPhone(phone);
|
|
||||||
// 检查用户可行性
|
|
||||||
checkUserIsEffective(loginUser);
|
|
||||||
|
|
||||||
|
|
||||||
String redisKey = CommonConstant.PHONE_REDIS_KEY_PRE+phone;
|
|
||||||
Object code = redisUtil.get(redisKey);
|
|
||||||
|
|
||||||
if (!captcha.equals(code)) {
|
|
||||||
//update-begin-author:taoyan date:2022-11-7 for: issues/4109 平台用户登录失败锁定用户
|
|
||||||
addLoginFailOvertimes(phone);
|
|
||||||
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("message", "手机验证码错误");
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!registeredClient.getAuthorizationGrantTypes().contains(authorizationGrantType)) {
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("message", "非法登录");
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
//由于在上面已验证过用户名、密码,现在构建一个已认证的对象UsernamePasswordAuthenticationToken
|
|
||||||
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = UsernamePasswordAuthenticationToken.authenticated(loginUser,clientPrincipal,new ArrayList<>());
|
|
||||||
|
|
||||||
DefaultOAuth2TokenContext.Builder tokenContextBuilder = DefaultOAuth2TokenContext.builder()
|
|
||||||
.registeredClient(registeredClient)
|
|
||||||
.principal(usernamePasswordAuthenticationToken)
|
|
||||||
.authorizationServerContext(AuthorizationServerContextHolder.getContext())
|
|
||||||
.authorizationGrantType(authorizationGrantType)
|
|
||||||
.authorizedScopes(requestScopeSet)
|
|
||||||
.authorizationGrant(phoneGrantAuthenticationToken);
|
|
||||||
|
|
||||||
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient)
|
|
||||||
.principalName(clientPrincipal.getName())
|
|
||||||
.authorizedScopes(requestScopeSet)
|
|
||||||
.attribute(Principal.class.getName(), loginUser.getUsername())
|
|
||||||
.authorizationGrantType(authorizationGrantType);
|
|
||||||
|
|
||||||
|
|
||||||
// ----- Access token -----
|
|
||||||
OAuth2TokenContext tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.ACCESS_TOKEN).build();
|
|
||||||
OAuth2Token generatedAccessToken = this.tokenGenerator.generate(tokenContext);
|
|
||||||
if (generatedAccessToken == null) {
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("message", "无法生成刷新token,请联系管理员。");
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
|
|
||||||
}
|
|
||||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
|
|
||||||
generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),
|
|
||||||
generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
|
|
||||||
if (generatedAccessToken instanceof ClaimAccessor) {
|
|
||||||
authorizationBuilder.token(accessToken, (metadata) -> {
|
|
||||||
metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME, ((ClaimAccessor) generatedAccessToken).getClaims());
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
authorizationBuilder.accessToken(accessToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----- Refresh token -----
|
|
||||||
OAuth2RefreshToken refreshToken = null;
|
|
||||||
if (registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.REFRESH_TOKEN) &&
|
|
||||||
// 不向公共客户端颁发刷新令牌
|
|
||||||
!clientPrincipal.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.NONE)) {
|
|
||||||
|
|
||||||
tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.REFRESH_TOKEN).build();
|
|
||||||
OAuth2Token generatedRefreshToken = this.tokenGenerator.generate(tokenContext);
|
|
||||||
if (!(generatedRefreshToken instanceof OAuth2RefreshToken)) {
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("message", "无法生成刷新token,请联系管理员。");
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
refreshToken = (OAuth2RefreshToken) generatedRefreshToken;
|
|
||||||
authorizationBuilder.refreshToken(refreshToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
OAuth2Authorization authorization = authorizationBuilder.build();
|
|
||||||
|
|
||||||
// 保存认证信息至redis
|
|
||||||
authorizationService.save(authorization);
|
|
||||||
|
|
||||||
baseCommonService.addLog("用户名: " + loginUser.getUsername() + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser);
|
|
||||||
|
|
||||||
JSONObject addition = new JSONObject(new LinkedHashMap<>());
|
|
||||||
addition.put("token", accessToken.getTokenValue());
|
|
||||||
// 设置租户
|
|
||||||
JSONObject jsonObject = commonAPI.setLoginTenant(loginUser.getUsername());
|
|
||||||
addition.putAll(jsonObject.getInnerMap());
|
|
||||||
|
|
||||||
// 设置登录用户信息
|
|
||||||
addition.put("userInfo", loginUser);
|
|
||||||
addition.put("sysAllDictItems", commonAPI.queryAllDictItems());
|
|
||||||
|
|
||||||
List<SysDepartModel> departs = commonAPI.queryUserDeparts(loginUser.getId());
|
|
||||||
addition.put("departs", departs);
|
|
||||||
if (departs == null || departs.size() == 0) {
|
|
||||||
addition.put("multi_depart", 0);
|
|
||||||
} else if (departs.size() == 1) {
|
|
||||||
commonAPI.updateUserDepart(loginUser.getUsername(), departs.get(0).getOrgCode(),null);
|
|
||||||
addition.put("multi_depart", 1);
|
|
||||||
} else {
|
|
||||||
//查询当前是否有登录部门
|
|
||||||
if(oConvertUtils.isEmpty(loginUser.getOrgCode())){
|
|
||||||
commonAPI.updateUserDepart(loginUser.getUsername(), departs.get(0).getOrgCode(),null);
|
|
||||||
}
|
|
||||||
addition.put("multi_depart", 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 兼容原有shiro登录结果处理
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("result", addition);
|
|
||||||
map.put("code", 200);
|
|
||||||
map.put("success", true);
|
|
||||||
map.put("timestamp", System.currentTimeMillis());
|
|
||||||
|
|
||||||
// 返回access_token、refresh_token以及其它信息给到前端
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> authentication) {
|
|
||||||
return PhoneGrantAuthenticationToken.class.isAssignableFrom(authentication);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static OAuth2ClientAuthenticationToken getAuthenticatedClientElseThrowInvalidClient(Authentication authentication) {
|
|
||||||
OAuth2ClientAuthenticationToken clientPrincipal = null;
|
|
||||||
if (OAuth2ClientAuthenticationToken.class.isAssignableFrom(authentication.getPrincipal().getClass())) {
|
|
||||||
clientPrincipal = (OAuth2ClientAuthenticationToken) authentication.getPrincipal();
|
|
||||||
}
|
|
||||||
if (clientPrincipal != null && clientPrincipal.isAuthenticated()) {
|
|
||||||
return clientPrincipal;
|
|
||||||
}
|
|
||||||
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_CLIENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录失败超出次数5 返回true
|
|
||||||
* @param username
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private boolean isLoginFailOvertimes(String username){
|
|
||||||
String key = CommonConstant.LOGIN_FAIL + username;
|
|
||||||
Object failTime = redisUtil.get(key);
|
|
||||||
if(failTime!=null){
|
|
||||||
Integer val = Integer.parseInt(failTime.toString());
|
|
||||||
if(val>5){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 记录登录失败次数
|
|
||||||
* @param username
|
|
||||||
*/
|
|
||||||
private void addLoginFailOvertimes(String username){
|
|
||||||
String key = CommonConstant.LOGIN_FAIL + username;
|
|
||||||
Object failTime = redisUtil.get(key);
|
|
||||||
Integer val = 0;
|
|
||||||
if(failTime!=null){
|
|
||||||
val = Integer.parseInt(failTime.toString());
|
|
||||||
}
|
|
||||||
// 10分钟
|
|
||||||
redisUtil.set(key, ++val, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验用户是否有效
|
|
||||||
*/
|
|
||||||
private void checkUserIsEffective(LoginUser loginUser) {
|
|
||||||
//情况1:根据用户信息查询,该用户不存在
|
|
||||||
if (Objects.isNull(loginUser)) {
|
|
||||||
baseCommonService.addLog("用户登录失败,用户不存在!", CommonConstant.LOG_TYPE_1, null);
|
|
||||||
throw new JeecgBootException("该用户不存在,请注册");
|
|
||||||
}
|
|
||||||
//情况2:根据用户信息查询,该用户已注销
|
|
||||||
//update-begin---author:王帅 Date:20200601 for:if条件永远为falsebug------------
|
|
||||||
if (CommonConstant.DEL_FLAG_1.equals(loginUser.getDelFlag())) {
|
|
||||||
//update-end---author:王帅 Date:20200601 for:if条件永远为falsebug------------
|
|
||||||
baseCommonService.addLog("用户登录失败,用户名:" + loginUser.getUsername() + "已注销!", CommonConstant.LOG_TYPE_1, null);
|
|
||||||
throw new JeecgBootException("该用户已注销");
|
|
||||||
}
|
|
||||||
//情况3:根据用户信息查询,该用户已冻结
|
|
||||||
if (CommonConstant.USER_FREEZE.equals(loginUser.getStatus())) {
|
|
||||||
baseCommonService.addLog("用户登录失败,用户名:" + loginUser.getUsername() + "已冻结!", CommonConstant.LOG_TYPE_1, null);
|
|
||||||
throw new JeecgBootException("该用户已冻结");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
package org.jeecg.config.security.phone;
|
|
||||||
|
|
||||||
import org.jeecg.config.security.LoginType;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 手机号模式认证专用token类型,方法spring authorization server进行认证流转,配合convert使用
|
|
||||||
* @author EightMonth
|
|
||||||
* @date 2024/1/1
|
|
||||||
*/
|
|
||||||
public class PhoneGrantAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken {
|
|
||||||
|
|
||||||
public PhoneGrantAuthenticationToken(Authentication clientPrincipal, Map<String, Object> additionalParameters) {
|
|
||||||
super(new AuthorizationGrantType(LoginType.PHONE), clientPrincipal, additionalParameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,187 +0,0 @@
|
|||||||
package org.jeecg.config.security.self;
|
|
||||||
|
|
||||||
import org.jeecg.common.api.CommonAPI;
|
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
|
||||||
import org.jeecg.common.exception.JeecgBoot401Exception;
|
|
||||||
import org.jeecg.common.exception.JeecgBootException;
|
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
|
||||||
import org.jeecg.common.util.RedisUtil;
|
|
||||||
import org.jeecg.config.JeecgBaseConfig;
|
|
||||||
import org.jeecg.modules.base.service.BaseCommonService;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Lazy;
|
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.security.oauth2.core.*;
|
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
import java.security.Principal;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自用生成token处理器,不对外开放,外部请求无法通过该方式生成token
|
|
||||||
* @author eightmonth@qq.com
|
|
||||||
* @date 2024/3/19 11:40
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class SelfAuthenticationProvider implements AuthenticationProvider {
|
|
||||||
|
|
||||||
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
|
|
||||||
|
|
||||||
private final OAuth2AuthorizationService authorizationService;
|
|
||||||
private final OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator;
|
|
||||||
@Lazy
|
|
||||||
@Autowired
|
|
||||||
private CommonAPI commonAPI;
|
|
||||||
@Autowired
|
|
||||||
private RedisUtil redisUtil;
|
|
||||||
@Autowired
|
|
||||||
private JeecgBaseConfig jeecgBaseConfig;
|
|
||||||
@Autowired
|
|
||||||
private BaseCommonService baseCommonService;
|
|
||||||
|
|
||||||
public SelfAuthenticationProvider(OAuth2AuthorizationService authorizationService, OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator) {
|
|
||||||
Assert.notNull(authorizationService, "authorizationService cannot be null");
|
|
||||||
Assert.notNull(tokenGenerator, "tokenGenerator cannot be null");
|
|
||||||
this.authorizationService = authorizationService;
|
|
||||||
this.tokenGenerator = tokenGenerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
|
||||||
SelfAuthenticationToken passwordGrantAuthenticationToken = (SelfAuthenticationToken) authentication;
|
|
||||||
Map<String, Object> additionalParameter = passwordGrantAuthenticationToken.getAdditionalParameters();
|
|
||||||
|
|
||||||
// 授权类型
|
|
||||||
AuthorizationGrantType authorizationGrantType = passwordGrantAuthenticationToken.getGrantType();
|
|
||||||
// 用户名
|
|
||||||
String username = (String) additionalParameter.get(OAuth2ParameterNames.USERNAME);
|
|
||||||
//请求参数权限范围
|
|
||||||
String requestScopesStr = "*";
|
|
||||||
//请求参数权限范围专场集合
|
|
||||||
Set<String> requestScopeSet = Stream.of(requestScopesStr.split(" ")).collect(Collectors.toSet());
|
|
||||||
|
|
||||||
OAuth2ClientAuthenticationToken clientPrincipal = getAuthenticatedClientElseThrowInvalidClient(passwordGrantAuthenticationToken);
|
|
||||||
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();
|
|
||||||
|
|
||||||
// 通过用户名获取用户信息
|
|
||||||
// LoginUser loginUser = commonAPI.getUserByName(username);
|
|
||||||
// 检查用户可行性
|
|
||||||
// checkUserIsEffective(loginUser);
|
|
||||||
|
|
||||||
//由于在上面已验证过用户名、密码,现在构建一个已认证的对象UsernamePasswordAuthenticationToken
|
|
||||||
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = UsernamePasswordAuthenticationToken.authenticated(username,clientPrincipal,new ArrayList<>());
|
|
||||||
|
|
||||||
DefaultOAuth2TokenContext.Builder tokenContextBuilder = DefaultOAuth2TokenContext.builder()
|
|
||||||
.registeredClient(registeredClient)
|
|
||||||
.principal(usernamePasswordAuthenticationToken)
|
|
||||||
.authorizationGrantType(authorizationGrantType)
|
|
||||||
.authorizedScopes(requestScopeSet)
|
|
||||||
.authorizationGrant(passwordGrantAuthenticationToken);
|
|
||||||
|
|
||||||
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient)
|
|
||||||
.principalName(clientPrincipal.getName())
|
|
||||||
.authorizedScopes(requestScopeSet)
|
|
||||||
.attribute(Principal.class.getName(), username)
|
|
||||||
.authorizationGrantType(authorizationGrantType);
|
|
||||||
|
|
||||||
|
|
||||||
// ----- Access token -----
|
|
||||||
OAuth2TokenContext tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.ACCESS_TOKEN).build();
|
|
||||||
OAuth2Token generatedAccessToken = this.tokenGenerator.generate(tokenContext);
|
|
||||||
if (generatedAccessToken == null) {
|
|
||||||
throw new JeecgBoot401Exception("无法生成刷新token,请联系管理员。");
|
|
||||||
}
|
|
||||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
|
|
||||||
generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),
|
|
||||||
generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
|
|
||||||
if (generatedAccessToken instanceof ClaimAccessor) {
|
|
||||||
authorizationBuilder.token(accessToken, (metadata) -> {
|
|
||||||
metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME, ((ClaimAccessor) generatedAccessToken).getClaims());
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
authorizationBuilder.accessToken(accessToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----- Refresh token -----
|
|
||||||
OAuth2RefreshToken refreshToken = null;
|
|
||||||
if (registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.REFRESH_TOKEN) &&
|
|
||||||
// 不向公共客户端颁发刷新令牌
|
|
||||||
!clientPrincipal.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.NONE)) {
|
|
||||||
|
|
||||||
tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.REFRESH_TOKEN).build();
|
|
||||||
OAuth2Token generatedRefreshToken = this.tokenGenerator.generate(tokenContext);
|
|
||||||
if (!(generatedRefreshToken instanceof OAuth2RefreshToken)) {
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("message", "无法生成刷新token,请联系管理员。");
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
refreshToken = (OAuth2RefreshToken) generatedRefreshToken;
|
|
||||||
authorizationBuilder.refreshToken(refreshToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
OAuth2Authorization authorization = authorizationBuilder.build();
|
|
||||||
|
|
||||||
// 保存认证信息至redis
|
|
||||||
authorizationService.save(authorization);
|
|
||||||
|
|
||||||
// 返回access_token、refresh_token以及其它信息给到前端
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> authentication) {
|
|
||||||
return SelfAuthenticationToken.class.isAssignableFrom(authentication);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static OAuth2ClientAuthenticationToken getAuthenticatedClientElseThrowInvalidClient(Authentication authentication) {
|
|
||||||
OAuth2ClientAuthenticationToken clientPrincipal = null;
|
|
||||||
if (OAuth2ClientAuthenticationToken.class.isAssignableFrom(authentication.getPrincipal().getClass())) {
|
|
||||||
clientPrincipal = (OAuth2ClientAuthenticationToken) authentication.getPrincipal();
|
|
||||||
}
|
|
||||||
if (clientPrincipal != null && clientPrincipal.isAuthenticated()) {
|
|
||||||
return clientPrincipal;
|
|
||||||
}
|
|
||||||
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_CLIENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验用户是否有效
|
|
||||||
*/
|
|
||||||
private void checkUserIsEffective(LoginUser loginUser) {
|
|
||||||
//情况1:根据用户信息查询,该用户不存在
|
|
||||||
if (Objects.isNull(loginUser)) {
|
|
||||||
baseCommonService.addLog("用户登录失败,用户不存在!", CommonConstant.LOG_TYPE_1, null);
|
|
||||||
throw new JeecgBootException("该用户不存在,请注册");
|
|
||||||
}
|
|
||||||
//情况2:根据用户信息查询,该用户已注销
|
|
||||||
//update-begin---author:王帅 Date:20200601 for:if条件永远为falsebug------------
|
|
||||||
if (CommonConstant.DEL_FLAG_1.equals(loginUser.getDelFlag())) {
|
|
||||||
//update-end---author:王帅 Date:20200601 for:if条件永远为falsebug------------
|
|
||||||
baseCommonService.addLog("用户登录失败,用户名:" + loginUser.getUsername() + "已注销!", CommonConstant.LOG_TYPE_1, null);
|
|
||||||
throw new JeecgBootException("该用户已注销");
|
|
||||||
}
|
|
||||||
//情况3:根据用户信息查询,该用户已冻结
|
|
||||||
if (CommonConstant.USER_FREEZE.equals(loginUser.getStatus())) {
|
|
||||||
baseCommonService.addLog("用户登录失败,用户名:" + loginUser.getUsername() + "已冻结!", CommonConstant.LOG_TYPE_1, null);
|
|
||||||
throw new JeecgBootException("该用户已冻结");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
package org.jeecg.config.security.self;
|
|
||||||
|
|
||||||
import org.jeecg.config.security.LoginType;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自用生成token,不支持对外请求,仅为程序内部生成token
|
|
||||||
* @author eightmonth
|
|
||||||
* @date 2024/3/19 11:37
|
|
||||||
*/
|
|
||||||
public class SelfAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken {
|
|
||||||
public SelfAuthenticationToken(Authentication clientPrincipal, Map<String, Object> additionalParameters) {
|
|
||||||
super(new AuthorizationGrantType(LoginType.SELF), clientPrincipal, additionalParameters);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
package org.jeecg.config.security.social;
|
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import org.jeecg.config.security.LoginType;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
|
||||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
|
||||||
import org.springframework.util.MultiValueMap;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 社交模式认证转换器,配合github、企业微信、钉钉、微信登录使用
|
|
||||||
* @author EightMonth
|
|
||||||
* @date 2024/1/1
|
|
||||||
*/
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class SocialGrantAuthenticationConvert implements AuthenticationConverter {
|
|
||||||
@Override
|
|
||||||
public Authentication convert(HttpServletRequest request) {
|
|
||||||
|
|
||||||
String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
|
|
||||||
if (!LoginType.SOCIAL.equals(grantType)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();
|
|
||||||
|
|
||||||
//从request中提取请求参数,然后存入MultiValueMap<String, String>
|
|
||||||
MultiValueMap<String, String> parameters = getParameters(request);
|
|
||||||
|
|
||||||
String token = parameters.getFirst("token");
|
|
||||||
if (!StringUtils.hasText(token)) {
|
|
||||||
throw new OAuth2AuthenticationException("无效请求,三方token不能为空!");
|
|
||||||
}
|
|
||||||
|
|
||||||
String source = parameters.getFirst("thirdType");
|
|
||||||
if (!StringUtils.hasText(source)) {
|
|
||||||
throw new OAuth2AuthenticationException("无效请求,三方来源不能为空!");
|
|
||||||
}
|
|
||||||
|
|
||||||
//收集要传入PhoneGrantAuthenticationToken构造方法的参数,
|
|
||||||
//该参数接下来在PhoneGrantAuthenticationProvider中使用
|
|
||||||
Map<String, Object> additionalParameters = new HashMap<>();
|
|
||||||
//遍历从request中提取的参数,排除掉grant_type、client_id、code等字段参数,其他参数收集到additionalParameters中
|
|
||||||
parameters.forEach((key, value) -> {
|
|
||||||
if (!key.equals(OAuth2ParameterNames.GRANT_TYPE) &&
|
|
||||||
!key.equals(OAuth2ParameterNames.CLIENT_ID) &&
|
|
||||||
!key.equals(OAuth2ParameterNames.CODE)) {
|
|
||||||
additionalParameters.put(key, value.get(0));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//返回自定义的PhoneGrantAuthenticationToken对象
|
|
||||||
return new SocialGrantAuthenticationToken(clientPrincipal, additionalParameters);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*从request中提取请求参数,然后存入MultiValueMap<String, String>
|
|
||||||
*/
|
|
||||||
private static MultiValueMap<String, String> getParameters(HttpServletRequest request) {
|
|
||||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
|
||||||
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>(parameterMap.size());
|
|
||||||
parameterMap.forEach((key, values) -> {
|
|
||||||
if (values.length > 0) {
|
|
||||||
for (String value : values) {
|
|
||||||
parameters.add(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,278 +0,0 @@
|
|||||||
package org.jeecg.config.security.social;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import com.auth0.jwt.JWT;
|
|
||||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.jeecg.common.api.CommonAPI;
|
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
|
||||||
import org.jeecg.common.exception.JeecgBootException;
|
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
|
||||||
import org.jeecg.common.system.vo.SysDepartModel;
|
|
||||||
import org.jeecg.common.util.RedisUtil;
|
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
|
||||||
import org.jeecg.config.JeecgBaseConfig;
|
|
||||||
import org.jeecg.config.security.password.PasswordGrantAuthenticationToken;
|
|
||||||
import org.jeecg.modules.base.service.BaseCommonService;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Lazy;
|
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.security.oauth2.core.*;
|
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.context.AuthorizationServerContextHolder;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
import java.security.Principal;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 社交模式认证处理器,负责处理该认证模式下的核心逻辑,配合github、企业微信、钉钉、微信登录使用
|
|
||||||
* @author EightMonth
|
|
||||||
* @date 2024/1/1
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
public class SocialGrantAuthenticationProvider implements AuthenticationProvider {
|
|
||||||
|
|
||||||
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
|
|
||||||
|
|
||||||
private final OAuth2AuthorizationService authorizationService;
|
|
||||||
private final OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator;
|
|
||||||
@Lazy
|
|
||||||
@Autowired
|
|
||||||
private CommonAPI commonAPI;
|
|
||||||
@Autowired
|
|
||||||
private RedisUtil redisUtil;
|
|
||||||
@Autowired
|
|
||||||
private JeecgBaseConfig jeecgBaseConfig;
|
|
||||||
@Autowired
|
|
||||||
private BaseCommonService baseCommonService;
|
|
||||||
|
|
||||||
public SocialGrantAuthenticationProvider(OAuth2AuthorizationService authorizationService, OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator) {
|
|
||||||
Assert.notNull(authorizationService, "authorizationService cannot be null");
|
|
||||||
Assert.notNull(tokenGenerator, "tokenGenerator cannot be null");
|
|
||||||
this.authorizationService = authorizationService;
|
|
||||||
this.tokenGenerator = tokenGenerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
|
||||||
SocialGrantAuthenticationToken socialGrantAuthenticationToken = (SocialGrantAuthenticationToken) authentication;
|
|
||||||
Map<String, Object> additionalParameter = socialGrantAuthenticationToken.getAdditionalParameters();
|
|
||||||
|
|
||||||
// 授权类型
|
|
||||||
AuthorizationGrantType authorizationGrantType = socialGrantAuthenticationToken.getGrantType();
|
|
||||||
// 三方token
|
|
||||||
String token = (String) additionalParameter.get("token");
|
|
||||||
// 三方来源
|
|
||||||
String source = (String) additionalParameter.get("thirdType");
|
|
||||||
|
|
||||||
//请求参数权限范围
|
|
||||||
String requestScopesStr = (String)additionalParameter.getOrDefault(OAuth2ParameterNames.SCOPE, "*");
|
|
||||||
//请求参数权限范围专场集合
|
|
||||||
Set<String> requestScopeSet = Stream.of(requestScopesStr.split(" ")).collect(Collectors.toSet());
|
|
||||||
|
|
||||||
DecodedJWT jwt = JWT.decode(token);
|
|
||||||
String username = jwt.getClaim("username").asString();
|
|
||||||
|
|
||||||
// 通过手机号获取用户信息
|
|
||||||
LoginUser loginUser = commonAPI.getUserByName(username);
|
|
||||||
// 检查用户可行性
|
|
||||||
checkUserIsEffective(loginUser);
|
|
||||||
|
|
||||||
OAuth2ClientAuthenticationToken clientPrincipal = getAuthenticatedClientElseThrowInvalidClient(socialGrantAuthenticationToken);
|
|
||||||
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();
|
|
||||||
|
|
||||||
if (!registeredClient.getAuthorizationGrantTypes().contains(authorizationGrantType)) {
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("message", "非法登录");
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//由于在上面已验证过用户名、密码,现在构建一个已认证的对象UsernamePasswordAuthenticationToken
|
|
||||||
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = UsernamePasswordAuthenticationToken.authenticated(loginUser,clientPrincipal,new ArrayList<>());
|
|
||||||
|
|
||||||
DefaultOAuth2TokenContext.Builder tokenContextBuilder = DefaultOAuth2TokenContext.builder()
|
|
||||||
.registeredClient(registeredClient)
|
|
||||||
.principal(usernamePasswordAuthenticationToken)
|
|
||||||
.authorizationServerContext(AuthorizationServerContextHolder.getContext())
|
|
||||||
.authorizationGrantType(authorizationGrantType)
|
|
||||||
.authorizedScopes(requestScopeSet)
|
|
||||||
.authorizationGrant(socialGrantAuthenticationToken);
|
|
||||||
|
|
||||||
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient)
|
|
||||||
.principalName(clientPrincipal.getName())
|
|
||||||
.authorizedScopes(requestScopeSet)
|
|
||||||
.attribute(Principal.class.getName(), loginUser.getUsername())
|
|
||||||
.authorizationGrantType(authorizationGrantType);
|
|
||||||
|
|
||||||
|
|
||||||
// ----- Access token -----
|
|
||||||
OAuth2TokenContext tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.ACCESS_TOKEN).build();
|
|
||||||
OAuth2Token generatedAccessToken = this.tokenGenerator.generate(tokenContext);
|
|
||||||
if (generatedAccessToken == null) {
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("message", "无法生成访问token,请联系管理系。");
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
|
|
||||||
|
|
||||||
}
|
|
||||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
|
|
||||||
generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),
|
|
||||||
generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
|
|
||||||
if (generatedAccessToken instanceof ClaimAccessor) {
|
|
||||||
authorizationBuilder.token(accessToken, (metadata) -> {
|
|
||||||
metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME, ((ClaimAccessor) generatedAccessToken).getClaims());
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
authorizationBuilder.accessToken(accessToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----- Refresh token -----
|
|
||||||
OAuth2RefreshToken refreshToken = null;
|
|
||||||
if (registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.REFRESH_TOKEN) &&
|
|
||||||
// 不向公共客户端颁发刷新令牌
|
|
||||||
!clientPrincipal.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.NONE)) {
|
|
||||||
|
|
||||||
tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.REFRESH_TOKEN).build();
|
|
||||||
OAuth2Token generatedRefreshToken = this.tokenGenerator.generate(tokenContext);
|
|
||||||
if (!(generatedRefreshToken instanceof OAuth2RefreshToken)) {
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("message", "无法生成刷新token,请联系管理员。");
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
refreshToken = (OAuth2RefreshToken) generatedRefreshToken;
|
|
||||||
authorizationBuilder.refreshToken(refreshToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
OAuth2Authorization authorization = authorizationBuilder.build();
|
|
||||||
|
|
||||||
// 保存认证信息至redis
|
|
||||||
authorizationService.save(authorization);
|
|
||||||
|
|
||||||
baseCommonService.addLog("用户名: " + loginUser.getUsername() + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser);
|
|
||||||
|
|
||||||
JSONObject addition = new JSONObject(new LinkedHashMap<>());
|
|
||||||
addition.put("token", accessToken.getTokenValue());
|
|
||||||
// 设置租户
|
|
||||||
JSONObject jsonObject = commonAPI.setLoginTenant(loginUser.getUsername());
|
|
||||||
addition.putAll(jsonObject.getInnerMap());
|
|
||||||
|
|
||||||
// 设置登录用户信息
|
|
||||||
addition.put("userInfo", loginUser);
|
|
||||||
addition.put("sysAllDictItems", commonAPI.queryAllDictItems());
|
|
||||||
|
|
||||||
List<SysDepartModel> departs = commonAPI.queryUserDeparts(loginUser.getId());
|
|
||||||
addition.put("departs", departs);
|
|
||||||
if (departs == null || departs.size() == 0) {
|
|
||||||
addition.put("multi_depart", 0);
|
|
||||||
} else if (departs.size() == 1) {
|
|
||||||
commonAPI.updateUserDepart(loginUser.getUsername(), departs.get(0).getOrgCode(),null);
|
|
||||||
addition.put("multi_depart", 1);
|
|
||||||
} else {
|
|
||||||
//查询当前是否有登录部门
|
|
||||||
if(oConvertUtils.isEmpty(loginUser.getOrgCode())){
|
|
||||||
commonAPI.updateUserDepart(loginUser.getUsername(), departs.get(0).getOrgCode(),null);
|
|
||||||
}
|
|
||||||
addition.put("multi_depart", 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 兼容原有shiro登录结果处理
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("result", addition);
|
|
||||||
map.put("code", 200);
|
|
||||||
map.put("success", true);
|
|
||||||
map.put("timestamp", System.currentTimeMillis());
|
|
||||||
|
|
||||||
|
|
||||||
// 返回access_token、refresh_token以及其它信息给到前端
|
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> authentication) {
|
|
||||||
return SocialGrantAuthenticationToken.class.isAssignableFrom(authentication);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static OAuth2ClientAuthenticationToken getAuthenticatedClientElseThrowInvalidClient(Authentication authentication) {
|
|
||||||
OAuth2ClientAuthenticationToken clientPrincipal = null;
|
|
||||||
if (OAuth2ClientAuthenticationToken.class.isAssignableFrom(authentication.getPrincipal().getClass())) {
|
|
||||||
clientPrincipal = (OAuth2ClientAuthenticationToken) authentication.getPrincipal();
|
|
||||||
}
|
|
||||||
if (clientPrincipal != null && clientPrincipal.isAuthenticated()) {
|
|
||||||
return clientPrincipal;
|
|
||||||
}
|
|
||||||
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_CLIENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录失败超出次数5 返回true
|
|
||||||
* @param username
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private boolean isLoginFailOvertimes(String username){
|
|
||||||
String key = CommonConstant.LOGIN_FAIL + username;
|
|
||||||
Object failTime = redisUtil.get(key);
|
|
||||||
if(failTime!=null){
|
|
||||||
Integer val = Integer.parseInt(failTime.toString());
|
|
||||||
if(val>5){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 记录登录失败次数
|
|
||||||
* @param username
|
|
||||||
*/
|
|
||||||
private void addLoginFailOvertimes(String username){
|
|
||||||
String key = CommonConstant.LOGIN_FAIL + username;
|
|
||||||
Object failTime = redisUtil.get(key);
|
|
||||||
Integer val = 0;
|
|
||||||
if(failTime!=null){
|
|
||||||
val = Integer.parseInt(failTime.toString());
|
|
||||||
}
|
|
||||||
// 10分钟
|
|
||||||
redisUtil.set(key, ++val, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验用户是否有效
|
|
||||||
*/
|
|
||||||
private void checkUserIsEffective(LoginUser loginUser) {
|
|
||||||
//情况1:根据用户信息查询,该用户不存在
|
|
||||||
if (Objects.isNull(loginUser)) {
|
|
||||||
baseCommonService.addLog("用户登录失败,用户不存在!", CommonConstant.LOG_TYPE_1, null);
|
|
||||||
throw new JeecgBootException("该用户不存在,请注册");
|
|
||||||
}
|
|
||||||
//情况2:根据用户信息查询,该用户已注销
|
|
||||||
//update-begin---author:王帅 Date:20200601 for:if条件永远为falsebug------------
|
|
||||||
if (CommonConstant.DEL_FLAG_1.equals(loginUser.getDelFlag())) {
|
|
||||||
//update-end---author:王帅 Date:20200601 for:if条件永远为falsebug------------
|
|
||||||
baseCommonService.addLog("用户登录失败,用户名:" + loginUser.getUsername() + "已注销!", CommonConstant.LOG_TYPE_1, null);
|
|
||||||
throw new JeecgBootException("该用户已注销");
|
|
||||||
}
|
|
||||||
//情况3:根据用户信息查询,该用户已冻结
|
|
||||||
if (CommonConstant.USER_FREEZE.equals(loginUser.getStatus())) {
|
|
||||||
baseCommonService.addLog("用户登录失败,用户名:" + loginUser.getUsername() + "已冻结!", CommonConstant.LOG_TYPE_1, null);
|
|
||||||
throw new JeecgBootException("该用户已冻结");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
package org.jeecg.config.security.social;
|
|
||||||
|
|
||||||
import org.jeecg.config.security.LoginType;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 社交模式认证专用token类型,方法spring authorization server进行认证流转,配合convert使用,配合github、企业微信、钉钉、微信登录使用
|
|
||||||
* @author EightMonth
|
|
||||||
* @date 2024/1/1
|
|
||||||
*/
|
|
||||||
public class SocialGrantAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken {
|
|
||||||
|
|
||||||
public SocialGrantAuthenticationToken(Authentication clientPrincipal, Map<String, Object> additionalParameters) {
|
|
||||||
super(new AuthorizationGrantType(LoginType.SOCIAL), clientPrincipal, additionalParameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
package org.jeecg.config.security.utils;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 认证信息工具类
|
|
||||||
* @author EightMonth
|
|
||||||
* @date 2024/1/10 17:03
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
public class SecureUtil {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过当前认证信息获取用户信息
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static LoginUser currentUser() {
|
|
||||||
String userInfoJson = SecurityContextHolder.getContext().getAuthentication().getName();
|
|
||||||
//log.info("SecureUtil.currentUser: {}", userInfoJson);
|
|
||||||
return JSONObject.parseObject(userInfoJson, LoginUser.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package org.jeecg.config.shiro;
|
||||||
|
|
||||||
|
import org.apache.shiro.authc.AuthenticationToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author Scott
|
||||||
|
* @create 2018-07-12 15:19
|
||||||
|
* @desc
|
||||||
|
**/
|
||||||
|
public class JwtToken implements AuthenticationToken {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private String token;
|
||||||
|
|
||||||
|
public JwtToken(String token) {
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getPrincipal() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getCredentials() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,386 @@
|
|||||||
|
package org.jeecg.config.shiro;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.servlet.DispatcherType;
|
||||||
|
import jakarta.servlet.Filter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
|
||||||
|
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
|
||||||
|
import org.apache.shiro.mgt.DefaultSubjectDAO;
|
||||||
|
import org.apache.shiro.mgt.SecurityManager;
|
||||||
|
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
|
||||||
|
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
|
||||||
|
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
|
||||||
|
import org.apache.shiro.spring.web.ShiroUrlPathHelper;
|
||||||
|
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
|
||||||
|
import org.crazycake.shiro.*;
|
||||||
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
|
import org.jeecg.config.JeecgBaseConfig;
|
||||||
|
import org.jeecg.config.shiro.filters.CustomShiroFilterFactoryBean;
|
||||||
|
import org.jeecg.config.shiro.filters.JwtFilter;
|
||||||
|
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||||
|
import org.springframework.context.annotation.*;
|
||||||
|
import org.springframework.core.annotation.AnnotationUtils;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||||
|
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||||
|
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.filter.DelegatingFilterProxy;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||||
|
import redis.clients.jedis.HostAndPort;
|
||||||
|
import redis.clients.jedis.JedisCluster;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author: Scott
|
||||||
|
* @date: 2018/2/7
|
||||||
|
* @description: shiro 配置类
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Configuration
|
||||||
|
public class ShiroConfig {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private LettuceConnectionFactory lettuceConnectionFactory;
|
||||||
|
@Autowired
|
||||||
|
private Environment env;
|
||||||
|
@Resource
|
||||||
|
private JeecgBaseConfig jeecgBaseConfig;
|
||||||
|
@Autowired(required = false)
|
||||||
|
private RedisProperties redisProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter Chain定义说明
|
||||||
|
*
|
||||||
|
* 1、一个URL可以配置多个Filter,使用逗号分隔
|
||||||
|
* 2、当设置多个过滤器时,全部验证通过,才视为通过
|
||||||
|
* 3、部分过滤器可指定参数,如perms,roles
|
||||||
|
*/
|
||||||
|
@Bean("shiroFilterFactoryBean")
|
||||||
|
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
|
||||||
|
CustomShiroFilterFactoryBean shiroFilterFactoryBean = new CustomShiroFilterFactoryBean();
|
||||||
|
shiroFilterFactoryBean.setSecurityManager(securityManager);
|
||||||
|
// 拦截器
|
||||||
|
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
|
||||||
|
|
||||||
|
//支持yml方式,配置拦截排除
|
||||||
|
if(jeecgBaseConfig!=null && jeecgBaseConfig.getShiro()!=null){
|
||||||
|
String shiroExcludeUrls = jeecgBaseConfig.getShiro().getExcludeUrls();
|
||||||
|
if(oConvertUtils.isNotEmpty(shiroExcludeUrls)){
|
||||||
|
String[] permissionUrl = shiroExcludeUrls.split(",");
|
||||||
|
for(String url : permissionUrl){
|
||||||
|
filterChainDefinitionMap.put(url,"anon");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置不会被拦截的链接 顺序判断
|
||||||
|
filterChainDefinitionMap.put("/sys/cas/client/validateLogin", "anon"); //cas验证登录
|
||||||
|
filterChainDefinitionMap.put("/sys/randomImage/**", "anon"); //登录验证码接口排除
|
||||||
|
filterChainDefinitionMap.put("/sys/checkCaptcha", "anon"); //登录验证码接口排除
|
||||||
|
filterChainDefinitionMap.put("/sys/smsCheckCaptcha", "anon"); //短信次数发送太多验证码排除
|
||||||
|
filterChainDefinitionMap.put("/sys/login", "anon"); //登录接口排除
|
||||||
|
filterChainDefinitionMap.put("/sys/mLogin", "anon"); //登录接口排除
|
||||||
|
filterChainDefinitionMap.put("/sys/logout", "anon"); //登出接口排除
|
||||||
|
filterChainDefinitionMap.put("/sys/thirdLogin/**", "anon"); //第三方登录
|
||||||
|
filterChainDefinitionMap.put("/sys/getEncryptedString", "anon"); //获取加密串
|
||||||
|
filterChainDefinitionMap.put("/sys/sms", "anon");//短信验证码
|
||||||
|
filterChainDefinitionMap.put("/sys/phoneLogin", "anon");//手机登录
|
||||||
|
filterChainDefinitionMap.put("/sys/user/checkOnlyUser", "anon");//校验用户是否存在
|
||||||
|
filterChainDefinitionMap.put("/sys/user/register", "anon");//用户注册
|
||||||
|
filterChainDefinitionMap.put("/sys/user/phoneVerification", "anon");//用户忘记密码验证手机号
|
||||||
|
filterChainDefinitionMap.put("/sys/user/passwordChange", "anon");//用户更改密码
|
||||||
|
filterChainDefinitionMap.put("/auth/2step-code", "anon");//登录验证码
|
||||||
|
filterChainDefinitionMap.put("/sys/common/static/**", "anon");//图片预览 &下载文件不限制token
|
||||||
|
filterChainDefinitionMap.put("/sys/common/pdf/**", "anon");//pdf预览
|
||||||
|
|
||||||
|
//filterChainDefinitionMap.put("/sys/common/view/**", "anon");//图片预览不限制token
|
||||||
|
//filterChainDefinitionMap.put("/sys/common/download/**", "anon");//文件下载不限制token
|
||||||
|
filterChainDefinitionMap.put("/generic/**", "anon");//pdf预览需要文件
|
||||||
|
|
||||||
|
filterChainDefinitionMap.put("/sys/getLoginQrcode/**", "anon"); //登录二维码
|
||||||
|
filterChainDefinitionMap.put("/sys/getQrcodeToken/**", "anon"); //监听扫码
|
||||||
|
filterChainDefinitionMap.put("/sys/checkAuth", "anon"); //授权接口排除
|
||||||
|
filterChainDefinitionMap.put("/openapi/call/**", "anon"); // 开放平台接口排除
|
||||||
|
|
||||||
|
// 代码逻辑说明: 排除静态资源后缀
|
||||||
|
filterChainDefinitionMap.put("/", "anon");
|
||||||
|
filterChainDefinitionMap.put("/doc.html", "anon");
|
||||||
|
filterChainDefinitionMap.put("/**/*.js", "anon");
|
||||||
|
filterChainDefinitionMap.put("/**/*.css", "anon");
|
||||||
|
filterChainDefinitionMap.put("/**/*.html", "anon");
|
||||||
|
filterChainDefinitionMap.put("/**/*.svg", "anon");
|
||||||
|
filterChainDefinitionMap.put("/**/*.pdf", "anon");
|
||||||
|
filterChainDefinitionMap.put("/**/*.jpg", "anon");
|
||||||
|
filterChainDefinitionMap.put("/**/*.png", "anon");
|
||||||
|
filterChainDefinitionMap.put("/**/*.gif", "anon");
|
||||||
|
filterChainDefinitionMap.put("/**/*.ico", "anon");
|
||||||
|
filterChainDefinitionMap.put("/**/*.ttf", "anon");
|
||||||
|
filterChainDefinitionMap.put("/**/*.woff", "anon");
|
||||||
|
filterChainDefinitionMap.put("/**/*.woff2", "anon");
|
||||||
|
|
||||||
|
filterChainDefinitionMap.put("/**/*.glb", "anon");
|
||||||
|
filterChainDefinitionMap.put("/**/*.wasm", "anon");
|
||||||
|
|
||||||
|
filterChainDefinitionMap.put("/druid/**", "anon");
|
||||||
|
filterChainDefinitionMap.put("/swagger-ui.html", "anon");
|
||||||
|
filterChainDefinitionMap.put("/swagger**/**", "anon");
|
||||||
|
filterChainDefinitionMap.put("/webjars/**", "anon");
|
||||||
|
filterChainDefinitionMap.put("/v3/**", "anon");
|
||||||
|
|
||||||
|
filterChainDefinitionMap.put("/sys/annountCement/show/**", "anon");
|
||||||
|
|
||||||
|
//积木报表排除
|
||||||
|
filterChainDefinitionMap.put("/jmreport/**", "anon");
|
||||||
|
filterChainDefinitionMap.put("/**/*.js.map", "anon");
|
||||||
|
filterChainDefinitionMap.put("/**/*.css.map", "anon");
|
||||||
|
|
||||||
|
//积木BI大屏和仪表盘排除
|
||||||
|
filterChainDefinitionMap.put("/drag/view", "anon");
|
||||||
|
filterChainDefinitionMap.put("/drag/page/queryById", "anon");
|
||||||
|
filterChainDefinitionMap.put("/drag/page/addVisitsNumber", "anon");
|
||||||
|
filterChainDefinitionMap.put("/drag/page/queryTemplateList", "anon");
|
||||||
|
filterChainDefinitionMap.put("/drag/share/view/**", "anon");
|
||||||
|
filterChainDefinitionMap.put("/drag/onlDragDatasetHead/getAllChartData", "anon");
|
||||||
|
filterChainDefinitionMap.put("/drag/onlDragDatasetHead/getTotalData", "anon");
|
||||||
|
filterChainDefinitionMap.put("/drag/onlDragDatasetHead/getMapDataByCode", "anon");
|
||||||
|
filterChainDefinitionMap.put("/drag/onlDragDatasetHead/getTotalDataByCompId", "anon");
|
||||||
|
filterChainDefinitionMap.put("/drag/mock/json/**", "anon");
|
||||||
|
filterChainDefinitionMap.put("/drag/onlDragDatasetHead/getDictByCodes", "anon");
|
||||||
|
filterChainDefinitionMap.put("/drag/onlDragDatasetHead/queryAllById", "anon");
|
||||||
|
filterChainDefinitionMap.put("/jimubi/view", "anon");
|
||||||
|
filterChainDefinitionMap.put("/jimubi/share/view/**", "anon");
|
||||||
|
|
||||||
|
//大屏模板例子
|
||||||
|
filterChainDefinitionMap.put("/test/bigScreen/**", "anon");
|
||||||
|
filterChainDefinitionMap.put("/bigscreen/template1/**", "anon");
|
||||||
|
filterChainDefinitionMap.put("/bigscreen/template2/**", "anon");
|
||||||
|
//filterChainDefinitionMap.put("/test/jeecgDemo/rabbitMqClientTest/**", "anon"); //MQ测试
|
||||||
|
//filterChainDefinitionMap.put("/test/jeecgDemo/html", "anon"); //模板页面
|
||||||
|
//filterChainDefinitionMap.put("/test/jeecgDemo/redis/**", "anon"); //redis测试
|
||||||
|
|
||||||
|
//websocket排除
|
||||||
|
filterChainDefinitionMap.put("/websocket/**", "anon");//系统通知和公告
|
||||||
|
filterChainDefinitionMap.put("/newsWebsocket/**", "anon");//CMS模块
|
||||||
|
filterChainDefinitionMap.put("/vxeSocket/**", "anon");//JVxeTable无痕刷新示例
|
||||||
|
//App vue3版本查询版本接口
|
||||||
|
filterChainDefinitionMap.put("/sys/version/app3version", "anon");
|
||||||
|
//仪表盘(按钮通信)
|
||||||
|
filterChainDefinitionMap.put("/dragChannelSocket/**","anon");
|
||||||
|
|
||||||
|
//性能监控——安全隐患泄露TOEKN(durid连接池也有)
|
||||||
|
//filterChainDefinitionMap.put("/actuator/**", "anon");
|
||||||
|
//测试模块排除
|
||||||
|
filterChainDefinitionMap.put("/test/seata/**", "anon");
|
||||||
|
|
||||||
|
//错误路径排除
|
||||||
|
filterChainDefinitionMap.put("/error", "anon");
|
||||||
|
// 企业微信证书排除
|
||||||
|
filterChainDefinitionMap.put("/WW_verify*", "anon");
|
||||||
|
|
||||||
|
// 添加自己的过滤器并且取名为jwt
|
||||||
|
Map<String, Filter> filterMap = new HashMap<String, Filter>(1);
|
||||||
|
//如果cloudServer为空 则说明是单体 需要加载跨域配置【微服务跨域切换】
|
||||||
|
Object cloudServer = env.getProperty(CommonConstant.CLOUD_SERVER_KEY);
|
||||||
|
filterMap.put("jwt", new JwtFilter(cloudServer==null));
|
||||||
|
shiroFilterFactoryBean.setFilters(filterMap);
|
||||||
|
// <!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边
|
||||||
|
filterChainDefinitionMap.put("/**", "jwt");
|
||||||
|
|
||||||
|
// 未授权界面返回JSON
|
||||||
|
shiroFilterFactoryBean.setUnauthorizedUrl("/sys/common/403");
|
||||||
|
shiroFilterFactoryBean.setLoginUrl("/sys/common/403");
|
||||||
|
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
|
||||||
|
return shiroFilterFactoryBean;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* spring过滤装饰器 <br/>
|
||||||
|
* 因为shiro的filter不支持异步请求,导致所有的异步请求都会报错. <br/>
|
||||||
|
* 所以需要用spring的FilterRegistrationBean再代理一下shiro的filter.为他扩展异步支持. <br/>
|
||||||
|
* 后续所有异步的接口都需要再这里增加registration.addUrlPatterns("/xxx/xxx");
|
||||||
|
* @return
|
||||||
|
* @author chenrui
|
||||||
|
* @date 2024/12/3 19:49
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public FilterRegistrationBean shiroFilterRegistration() {
|
||||||
|
FilterRegistrationBean registration = new FilterRegistrationBean();
|
||||||
|
registration.setFilter(new DelegatingFilterProxy("shiroFilterFactoryBean"));
|
||||||
|
registration.setEnabled(true);
|
||||||
|
// 代码逻辑说明: [issues/7491]运行耗时长,效率慢
|
||||||
|
registration.addUrlPatterns("/test/ai/chat/send");
|
||||||
|
registration.addUrlPatterns("/airag/flow/run");
|
||||||
|
registration.addUrlPatterns("/airag/flow/debug");
|
||||||
|
registration.addUrlPatterns("/airag/chat/send");
|
||||||
|
registration.addUrlPatterns("/airag/app/debug");
|
||||||
|
registration.addUrlPatterns("/airag/app/prompt/generate");
|
||||||
|
registration.addUrlPatterns("/airag/chat/receive/**");
|
||||||
|
//支持异步
|
||||||
|
registration.setAsyncSupported(true);
|
||||||
|
registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC);
|
||||||
|
return registration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean("securityManager")
|
||||||
|
public DefaultWebSecurityManager securityManager(ShiroRealm myRealm) {
|
||||||
|
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
|
||||||
|
securityManager.setRealm(myRealm);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 关闭shiro自带的session,详情见文档
|
||||||
|
* http://shiro.apache.org/session-management.html#SessionManagement-
|
||||||
|
* StatelessApplications%28Sessionless%29
|
||||||
|
*/
|
||||||
|
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
|
||||||
|
DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
|
||||||
|
defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
|
||||||
|
subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
|
||||||
|
securityManager.setSubjectDAO(subjectDAO);
|
||||||
|
//自定义缓存实现,使用redis
|
||||||
|
securityManager.setCacheManager(redisCacheManager());
|
||||||
|
return securityManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下面的代码是添加注解支持
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@DependsOn("lifecycleBeanPostProcessor")
|
||||||
|
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
|
||||||
|
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
|
||||||
|
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
|
||||||
|
/**
|
||||||
|
* 解决重复代理问题 github#994
|
||||||
|
* 添加前缀判断 不匹配 任何Advisor
|
||||||
|
*/
|
||||||
|
defaultAdvisorAutoProxyCreator.setUsePrefix(true);
|
||||||
|
defaultAdvisorAutoProxyCreator.setAdvisorBeanNamePrefix("_no_advisor");
|
||||||
|
return defaultAdvisorAutoProxyCreator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
|
||||||
|
return new LifecycleBeanPostProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
|
||||||
|
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
|
||||||
|
advisor.setSecurityManager(securityManager);
|
||||||
|
return advisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cacheManager 缓存 redis实现
|
||||||
|
* 使用的是shiro-redis开源插件
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public RedisCacheManager redisCacheManager() {
|
||||||
|
log.info("===============(1)创建缓存管理器RedisCacheManager");
|
||||||
|
RedisCacheManager redisCacheManager = new RedisCacheManager();
|
||||||
|
redisCacheManager.setRedisManager(redisManager());
|
||||||
|
//redis中针对不同用户缓存(此处的id需要对应user实体中的id字段,用于唯一标识)
|
||||||
|
redisCacheManager.setPrincipalIdFieldName("id");
|
||||||
|
//用户权限信息缓存时间
|
||||||
|
redisCacheManager.setExpire(200000);
|
||||||
|
return redisCacheManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RedisConfig在项目starter项目中
|
||||||
|
* jeecg-boot-starter-github\jeecg-boot-common\src\main\java\org\jeecg\common\modules\redis\config\RedisConfig.java
|
||||||
|
*
|
||||||
|
* 配置shiro redisManager
|
||||||
|
* 使用的是shiro-redis开源插件
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public IRedisManager redisManager() {
|
||||||
|
log.info("===============(2)创建RedisManager,连接Redis..");
|
||||||
|
IRedisManager manager;
|
||||||
|
// sentinel cluster redis(【issues/5569】shiro集成 redis 不支持 sentinel 方式部署的redis集群 #5569)
|
||||||
|
if (Objects.nonNull(redisProperties)
|
||||||
|
&& Objects.nonNull(redisProperties.getSentinel())
|
||||||
|
&& !CollectionUtils.isEmpty(redisProperties.getSentinel().getNodes())) {
|
||||||
|
RedisSentinelManager sentinelManager = new RedisSentinelManager();
|
||||||
|
sentinelManager.setMasterName(redisProperties.getSentinel().getMaster());
|
||||||
|
sentinelManager.setHost(String.join(",", redisProperties.getSentinel().getNodes()));
|
||||||
|
sentinelManager.setPassword(redisProperties.getPassword());
|
||||||
|
sentinelManager.setDatabase(redisProperties.getDatabase());
|
||||||
|
|
||||||
|
return sentinelManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
// redis 单机支持,在集群为空,或者集群无机器时候使用 add by jzyadmin@163.com
|
||||||
|
if (lettuceConnectionFactory.getClusterConfiguration() == null || lettuceConnectionFactory.getClusterConfiguration().getClusterNodes().isEmpty()) {
|
||||||
|
RedisManager redisManager = new RedisManager();
|
||||||
|
redisManager.setHost(lettuceConnectionFactory.getHostName() + ":" + lettuceConnectionFactory.getPort());
|
||||||
|
//(lettuceConnectionFactory.getPort());
|
||||||
|
redisManager.setDatabase(lettuceConnectionFactory.getDatabase());
|
||||||
|
redisManager.setTimeout(0);
|
||||||
|
if (!StringUtils.isEmpty(lettuceConnectionFactory.getPassword())) {
|
||||||
|
redisManager.setPassword(lettuceConnectionFactory.getPassword());
|
||||||
|
}
|
||||||
|
manager = redisManager;
|
||||||
|
}else{
|
||||||
|
// redis集群支持,优先使用集群配置
|
||||||
|
RedisClusterManager redisManager = new RedisClusterManager();
|
||||||
|
Set<HostAndPort> portSet = new HashSet<>();
|
||||||
|
lettuceConnectionFactory.getClusterConfiguration().getClusterNodes().forEach(node -> portSet.add(new HostAndPort(node.getHost() , node.getPort())));
|
||||||
|
//update-begin--Author:scott Date:20210531 for:修改集群模式下未设置redis密码的bug issues/I3QNIC
|
||||||
|
if (oConvertUtils.isNotEmpty(lettuceConnectionFactory.getPassword())) {
|
||||||
|
JedisCluster jedisCluster = new JedisCluster(portSet, 2000, 2000, 5,
|
||||||
|
lettuceConnectionFactory.getPassword(), new GenericObjectPoolConfig());
|
||||||
|
redisManager.setPassword(lettuceConnectionFactory.getPassword());
|
||||||
|
redisManager.setJedisCluster(jedisCluster);
|
||||||
|
} else {
|
||||||
|
JedisCluster jedisCluster = new JedisCluster(portSet);
|
||||||
|
redisManager.setJedisCluster(jedisCluster);
|
||||||
|
}
|
||||||
|
manager = redisManager;
|
||||||
|
}
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解决 ShiroRequestMappingConfig 获取 requestMappingHandlerMapping Bean 冲突
|
||||||
|
* spring-boot-autoconfigure:3.4.5 和 spring-boot-actuator-autoconfigure:3.4.5
|
||||||
|
*/
|
||||||
|
@Primary
|
||||||
|
@Bean
|
||||||
|
public RequestMappingHandlerMapping overridedRequestMappingHandlerMapping() {
|
||||||
|
RequestMappingHandlerMapping mapping = new RequestMappingHandlerMapping();
|
||||||
|
mapping.setUrlPathHelper(new ShiroUrlPathHelper());
|
||||||
|
return mapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> rebuildUrl(String[] bases, String[] uris) {
|
||||||
|
List<String> urls = new ArrayList<>();
|
||||||
|
for (String base : bases) {
|
||||||
|
for (String uri : uris) {
|
||||||
|
urls.add(prefix(base)+prefix(uri));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return urls;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String prefix(String seg) {
|
||||||
|
return seg.startsWith("/") ? seg : "/"+seg;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,239 @@
|
|||||||
|
package org.jeecg.config.shiro;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.shiro.authc.AuthenticationException;
|
||||||
|
import org.apache.shiro.authc.AuthenticationInfo;
|
||||||
|
import org.apache.shiro.authc.AuthenticationToken;
|
||||||
|
import org.apache.shiro.authc.SimpleAuthenticationInfo;
|
||||||
|
import org.apache.shiro.authz.AuthorizationInfo;
|
||||||
|
import org.apache.shiro.authz.SimpleAuthorizationInfo;
|
||||||
|
import org.apache.shiro.realm.AuthorizingRealm;
|
||||||
|
import org.apache.shiro.subject.PrincipalCollection;
|
||||||
|
import org.jeecg.common.api.CommonAPI;
|
||||||
|
import org.jeecg.common.config.TenantContext;
|
||||||
|
import org.jeecg.common.constant.CacheConstant;
|
||||||
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
|
import org.jeecg.common.system.util.JwtUtil;
|
||||||
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
|
import org.jeecg.common.util.RedisUtil;
|
||||||
|
import org.jeecg.common.util.SpringContextUtils;
|
||||||
|
import org.jeecg.common.util.TokenUtils;
|
||||||
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
|
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.context.annotation.Role;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 用户登录鉴权和获取用户授权
|
||||||
|
* @Author: Scott
|
||||||
|
* @Date: 2019-4-23 8:13
|
||||||
|
* @Version: 1.1
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
public class ShiroRealm extends AuthorizingRealm {
|
||||||
|
@Lazy
|
||||||
|
@Resource
|
||||||
|
private CommonAPI commonApi;
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
@Resource
|
||||||
|
private RedisUtil redisUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 必须重写此方法,不然Shiro会报错
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean supports(AuthenticationToken token) {
|
||||||
|
return token instanceof JwtToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 权限信息认证(包括角色以及权限)是用户访问controller的时候才进行验证(redis存储的此处权限信息)
|
||||||
|
* 触发检测用户权限时才会调用此方法,例如checkRole,checkPermission
|
||||||
|
*
|
||||||
|
* @param principals 身份信息
|
||||||
|
* @return AuthorizationInfo 权限信息
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
|
||||||
|
log.debug("===============Shiro权限认证开始============ [ roles、permissions]==========");
|
||||||
|
String username = null;
|
||||||
|
String userId = null;
|
||||||
|
if (principals != null) {
|
||||||
|
LoginUser sysUser = (LoginUser) principals.getPrimaryPrincipal();
|
||||||
|
username = sysUser.getUsername();
|
||||||
|
userId = sysUser.getId();
|
||||||
|
}
|
||||||
|
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
|
||||||
|
|
||||||
|
// 设置用户拥有的角色集合,比如“admin,test”
|
||||||
|
Set<String> roleSet = commonApi.queryUserRolesById(userId);
|
||||||
|
//System.out.println(roleSet.toString());
|
||||||
|
info.setRoles(roleSet);
|
||||||
|
|
||||||
|
// 设置用户拥有的权限集合,比如“sys:role:add,sys:user:add”
|
||||||
|
Set<String> permissionSet = commonApi.queryUserAuths(userId);
|
||||||
|
info.addStringPermissions(permissionSet);
|
||||||
|
//System.out.println(permissionSet);
|
||||||
|
log.debug("===============Shiro权限认证成功==============");
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户信息认证是在用户进行登录的时候进行验证(不存redis)
|
||||||
|
* 也就是说验证用户输入的账号和密码是否正确,错误抛出异常
|
||||||
|
*
|
||||||
|
* @param auth 用户登录的账号密码信息
|
||||||
|
* @return 返回封装了用户信息的 AuthenticationInfo 实例
|
||||||
|
* @throws AuthenticationException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
|
||||||
|
log.debug("===============Shiro身份认证开始============doGetAuthenticationInfo==========");
|
||||||
|
String token = (String) auth.getCredentials();
|
||||||
|
if (token == null) {
|
||||||
|
HttpServletRequest req = SpringContextUtils.getHttpServletRequest();
|
||||||
|
log.info("————————身份认证失败——————————IP地址: "+ oConvertUtils.getIpAddrByRequest(req) +",URL:"+req.getRequestURI());
|
||||||
|
throw new AuthenticationException("token为空!");
|
||||||
|
}
|
||||||
|
// 校验token有效性
|
||||||
|
LoginUser loginUser = null;
|
||||||
|
try {
|
||||||
|
loginUser = this.checkUserTokenIsEffect(token);
|
||||||
|
} catch (AuthenticationException e) {
|
||||||
|
log.error("—————校验 check token 失败——————————"+ e.getMessage(), e);
|
||||||
|
// 重新抛出异常,让JwtFilter统一处理,避免返回两次错误响应
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
return new SimpleAuthenticationInfo(loginUser, token, getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验token的有效性
|
||||||
|
*
|
||||||
|
* @param token
|
||||||
|
*/
|
||||||
|
public LoginUser checkUserTokenIsEffect(String token) throws AuthenticationException {
|
||||||
|
// 解密获得username,用于和数据库进行对比
|
||||||
|
String username = JwtUtil.getUsername(token);
|
||||||
|
if (username == null) {
|
||||||
|
throw new AuthenticationException("Token非法无效!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询用户信息
|
||||||
|
log.debug("———校验token是否有效————checkUserTokenIsEffect——————— "+ token);
|
||||||
|
LoginUser loginUser = TokenUtils.getLoginUser(username, commonApi, redisUtil);
|
||||||
|
//LoginUser loginUser = commonApi.getUserByName(username);
|
||||||
|
if (loginUser == null) {
|
||||||
|
throw new AuthenticationException("用户不存在!");
|
||||||
|
}
|
||||||
|
// 判断用户状态
|
||||||
|
if (loginUser.getStatus() != 1) {
|
||||||
|
throw new AuthenticationException("账号已被锁定,请联系管理员!");
|
||||||
|
}
|
||||||
|
// 校验token是否超时失效 & 或者账号密码是否错误
|
||||||
|
if (!jwtTokenRefresh(token, username, loginUser.getPassword())) {
|
||||||
|
// 用户登录Token过期提示信息
|
||||||
|
String userLoginTokenErrorMsg = oConvertUtils.getString(redisUtil.get(CommonConstant.PREFIX_USER_TOKEN_ERROR_MSG + token));
|
||||||
|
throw new AuthenticationException(oConvertUtils.isEmpty(userLoginTokenErrorMsg)? CommonConstant.TOKEN_IS_INVALID_MSG: userLoginTokenErrorMsg);
|
||||||
|
}
|
||||||
|
// 代码逻辑说明: 校验用户的tenant_id和前端传过来的是否一致
|
||||||
|
String userTenantIds = loginUser.getRelTenantIds();
|
||||||
|
if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL && oConvertUtils.isNotEmpty(userTenantIds)){
|
||||||
|
String contextTenantId = TenantContext.getTenant();
|
||||||
|
log.debug("登录租户:" + contextTenantId);
|
||||||
|
log.debug("用户拥有那些租户:" + userTenantIds);
|
||||||
|
//登录用户无租户,前端header中租户ID值为 0
|
||||||
|
String str ="0";
|
||||||
|
if(oConvertUtils.isNotEmpty(contextTenantId) && !str.equals(contextTenantId)){
|
||||||
|
// 代码逻辑说明: /issues/I4O14W 用户租户信息变更判断漏洞
|
||||||
|
String[] arr = userTenantIds.split(",");
|
||||||
|
if(!oConvertUtils.isIn(contextTenantId, arr)){
|
||||||
|
boolean isAuthorization = false;
|
||||||
|
//========================================================================
|
||||||
|
// 查询用户信息(如果租户不匹配从数据库中重新查询一次用户信息)
|
||||||
|
String loginUserKey = CacheConstant.SYS_USERS_CACHE + "::" + username;
|
||||||
|
redisUtil.del(loginUserKey);
|
||||||
|
LoginUser loginUserFromDb = commonApi.getUserByName(username);
|
||||||
|
if (oConvertUtils.isNotEmpty(loginUserFromDb.getRelTenantIds())) {
|
||||||
|
String[] newArray = loginUserFromDb.getRelTenantIds().split(",");
|
||||||
|
if (oConvertUtils.isIn(contextTenantId, newArray)) {
|
||||||
|
isAuthorization = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
//*********************************************
|
||||||
|
if(!isAuthorization){
|
||||||
|
log.info("租户异常——登录租户:" + contextTenantId);
|
||||||
|
log.info("租户异常——用户拥有租户组:" + userTenantIds);
|
||||||
|
throw new AuthenticationException("登录租户授权变更,请重新登陆!");
|
||||||
|
}
|
||||||
|
//*********************************************
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return loginUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JWTToken刷新生命周期 (实现: 用户在线操作不掉线功能)
|
||||||
|
* 1、登录成功后将用户的JWT生成的Token作为k、v存储到cache缓存里面(这时候k、v值一样),缓存有效期设置为Jwt有效时间的2倍
|
||||||
|
* 2、当该用户再次请求时,通过JWTFilter层层校验之后会进入到doGetAuthenticationInfo进行身份验证
|
||||||
|
* 3、当该用户这次请求jwt生成的token值已经超时,但该token对应cache中的k还是存在,则表示该用户一直在操作只是JWT的token失效了,程序会给token对应的k映射的v值重新生成JWTToken并覆盖v值,该缓存生命周期重新计算
|
||||||
|
* 4、当该用户这次请求jwt在生成的token值已经超时,并在cache中不存在对应的k,则表示该用户账户空闲超时,返回用户信息已失效,请重新登录。
|
||||||
|
* 注意: 前端请求Header中设置Authorization保持不变,校验有效性以缓存中的token为准。
|
||||||
|
* 用户过期时间 = Jwt有效时间 * 2。
|
||||||
|
*
|
||||||
|
* @param userName
|
||||||
|
* @param passWord
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean jwtTokenRefresh(String token, String userName, String passWord) {
|
||||||
|
String cacheToken = String.valueOf(redisUtil.get(CommonConstant.PREFIX_USER_TOKEN + token));
|
||||||
|
if (oConvertUtils.isNotEmpty(cacheToken)) {
|
||||||
|
// 校验token有效性
|
||||||
|
if (!JwtUtil.verify(cacheToken, userName, passWord)) {
|
||||||
|
// 从token中解析客户端类型,保持续期时使用相同的客户端类型
|
||||||
|
String clientType = JwtUtil.getClientType(token);
|
||||||
|
String newAuthorization = JwtUtil.sign(userName, passWord, clientType);
|
||||||
|
// 根据客户端类型设置对应的缓存有效时间
|
||||||
|
long expireTime = CommonConstant.CLIENT_TYPE_APP.equalsIgnoreCase(clientType)
|
||||||
|
? JwtUtil.APP_EXPIRE_TIME * 2 / 1000
|
||||||
|
: JwtUtil.EXPIRE_TIME * 2 / 1000;
|
||||||
|
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, newAuthorization);
|
||||||
|
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, expireTime);
|
||||||
|
log.debug("——————————用户在线操作,更新token保证不掉线—————————jwtTokenRefresh——————— "+ token);
|
||||||
|
}
|
||||||
|
// else {
|
||||||
|
// // 设置超时时间
|
||||||
|
// redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, cacheToken);
|
||||||
|
// redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 1000);
|
||||||
|
// }
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//redis中不存在此TOEKN,说明token非法返回false
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除当前用户的权限认证缓存
|
||||||
|
*
|
||||||
|
* @param principals 权限信息
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void clearCache(PrincipalCollection principals) {
|
||||||
|
super.clearCache(principals);
|
||||||
|
// 代码逻辑说明: 【TV360X-1320】分配权限必须退出重新登录才生效,造成很多用户困扰---
|
||||||
|
super.clearCachedAuthorizationInfo(principals);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,77 @@
|
|||||||
|
package org.jeecg.config.shiro.filters;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
|
||||||
|
import org.apache.shiro.web.filter.InvalidRequestFilter;
|
||||||
|
import org.apache.shiro.web.filter.mgt.DefaultFilter;
|
||||||
|
import org.apache.shiro.web.filter.mgt.FilterChainManager;
|
||||||
|
import org.apache.shiro.web.filter.mgt.FilterChainResolver;
|
||||||
|
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
|
||||||
|
import org.apache.shiro.web.mgt.WebSecurityManager;
|
||||||
|
import org.apache.shiro.web.servlet.AbstractShiroFilter;
|
||||||
|
import org.apache.shiro.mgt.SecurityManager;
|
||||||
|
import org.springframework.beans.factory.BeanInitializationException;
|
||||||
|
|
||||||
|
import jakarta.servlet.Filter;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义ShiroFilterFactoryBean解决资源中文路径问题
|
||||||
|
* @author: jeecg-boot
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class CustomShiroFilterFactoryBean extends ShiroFilterFactoryBean {
|
||||||
|
@Override
|
||||||
|
public Class getObjectType() {
|
||||||
|
return MySpringShiroFilter.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AbstractShiroFilter createInstance() throws Exception {
|
||||||
|
|
||||||
|
SecurityManager securityManager = getSecurityManager();
|
||||||
|
if (securityManager == null) {
|
||||||
|
String msg = "SecurityManager property must be set.";
|
||||||
|
throw new BeanInitializationException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(securityManager instanceof WebSecurityManager)) {
|
||||||
|
String msg = "The security manager does not implement the WebSecurityManager interface.";
|
||||||
|
throw new BeanInitializationException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterChainManager manager = createFilterChainManager();
|
||||||
|
//Expose the constructed FilterChainManager by first wrapping it in a
|
||||||
|
// FilterChainResolver implementation. The AbstractShiroFilter implementations
|
||||||
|
// do not know about FilterChainManagers - only resolvers:
|
||||||
|
PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
|
||||||
|
chainResolver.setFilterChainManager(manager);
|
||||||
|
|
||||||
|
Map<String, Filter> filterMap = manager.getFilters();
|
||||||
|
Filter invalidRequestFilter = filterMap.get(DefaultFilter.invalidRequest.name());
|
||||||
|
if (invalidRequestFilter instanceof InvalidRequestFilter) {
|
||||||
|
//此处是关键,设置false跳过URL携带中文400,servletPath中文校验bug
|
||||||
|
((InvalidRequestFilter) invalidRequestFilter).setBlockNonAscii(false);
|
||||||
|
}
|
||||||
|
//Now create a concrete ShiroFilter instance and apply the acquired SecurityManager and built
|
||||||
|
//FilterChainResolver. It doesn't matter that the instance is an anonymous inner class
|
||||||
|
//here - we're just using it because it is a concrete AbstractShiroFilter instance that accepts
|
||||||
|
//injection of the SecurityManager and FilterChainResolver:
|
||||||
|
return new MySpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class MySpringShiroFilter extends AbstractShiroFilter {
|
||||||
|
protected MySpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) {
|
||||||
|
if (webSecurityManager == null) {
|
||||||
|
throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
|
||||||
|
} else {
|
||||||
|
this.setSecurityManager(webSecurityManager);
|
||||||
|
if (resolver != null) {
|
||||||
|
this.setFilterChainResolver(resolver);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,132 @@
|
|||||||
|
package org.jeecg.config.shiro.filters;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
|
||||||
|
import org.jeecg.common.config.TenantContext;
|
||||||
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
|
import org.jeecg.common.system.util.JwtUtil;
|
||||||
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
|
import org.jeecg.config.shiro.JwtToken;
|
||||||
|
import org.jeecg.config.shiro.ignore.InMemoryIgnoreAuth;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
|
||||||
|
import jakarta.servlet.ServletRequest;
|
||||||
|
import jakarta.servlet.ServletResponse;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 鉴权登录拦截器
|
||||||
|
* @Author: Scott
|
||||||
|
* @Date: 2018/10/7
|
||||||
|
**/
|
||||||
|
@Slf4j
|
||||||
|
public class JwtFilter extends BasicHttpAuthenticationFilter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认开启跨域设置(使用单体)
|
||||||
|
* 微服务情况下,此属性设置为false
|
||||||
|
*/
|
||||||
|
private boolean allowOrigin = true;
|
||||||
|
|
||||||
|
public JwtFilter(){}
|
||||||
|
public JwtFilter(boolean allowOrigin){
|
||||||
|
this.allowOrigin = allowOrigin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行登录认证
|
||||||
|
*
|
||||||
|
* @param request
|
||||||
|
* @param response
|
||||||
|
* @param mappedValue
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
|
||||||
|
try {
|
||||||
|
// 判断当前路径是不是注解了@IngoreAuth路径,如果是,则放开验证
|
||||||
|
if (InMemoryIgnoreAuth.contains(((HttpServletRequest) request).getServletPath())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
executeLogin(request, response);
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 使用异常中的具体错误信息,保留"不允许同一账号多地同时登录"等具体提示
|
||||||
|
String errorMsg = e.getMessage();
|
||||||
|
if (oConvertUtils.isEmpty(errorMsg)) {
|
||||||
|
errorMsg = CommonConstant.TOKEN_IS_INVALID_MSG;
|
||||||
|
}
|
||||||
|
JwtUtil.responseError((HttpServletResponse)response, 401, errorMsg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
|
||||||
|
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
|
||||||
|
String token = httpServletRequest.getHeader(CommonConstant.X_ACCESS_TOKEN);
|
||||||
|
// 代码逻辑说明: JT-355 OA聊天添加token验证,获取token参数
|
||||||
|
if (oConvertUtils.isEmpty(token)) {
|
||||||
|
token = httpServletRequest.getParameter("token");
|
||||||
|
}
|
||||||
|
|
||||||
|
JwtToken jwtToken = new JwtToken(token);
|
||||||
|
// 提交给realm进行登入,如果错误他会抛出异常并被捕获
|
||||||
|
getSubject(request, response).login(jwtToken);
|
||||||
|
// 如果没有抛出异常则代表登入成功,返回true
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对跨域提供支持
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
|
||||||
|
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
|
||||||
|
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
|
||||||
|
if(allowOrigin){
|
||||||
|
httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, httpServletRequest.getHeader(HttpHeaders.ORIGIN));
|
||||||
|
// 允许客户端请求方法
|
||||||
|
httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET,POST,OPTIONS,PUT,DELETE");
|
||||||
|
// 允许客户端提交的Header
|
||||||
|
String requestHeaders = httpServletRequest.getHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS);
|
||||||
|
if (StringUtils.isNotEmpty(requestHeaders)) {
|
||||||
|
httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders);
|
||||||
|
}
|
||||||
|
// 允许客户端携带凭证信息(是否允许发送Cookie)
|
||||||
|
httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
|
||||||
|
}
|
||||||
|
// 跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态
|
||||||
|
if (RequestMethod.OPTIONS.name().equalsIgnoreCase(httpServletRequest.getMethod())) {
|
||||||
|
httpServletResponse.setStatus(HttpStatus.OK.value());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 代码逻辑说明: 多租户用到
|
||||||
|
String tenantId = httpServletRequest.getHeader(CommonConstant.TENANT_ID);
|
||||||
|
TenantContext.setTenant(tenantId);
|
||||||
|
|
||||||
|
return super.preHandle(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JwtFilter中ThreadLocal需要及时清除 #3634
|
||||||
|
*
|
||||||
|
* @param request
|
||||||
|
* @param response
|
||||||
|
* @param exception
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void afterCompletion(ServletRequest request, ServletResponse response, Exception exception) throws Exception {
|
||||||
|
//log.info("------清空线程中多租户的ID={}------",TenantContext.getTenant());
|
||||||
|
TenantContext.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
package org.jeecg.config.shiro.filters;
|
||||||
|
|
||||||
|
import jakarta.servlet.ServletRequest;
|
||||||
|
import jakarta.servlet.ServletResponse;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.apache.shiro.subject.Subject;
|
||||||
|
import org.apache.shiro.web.filter.AccessControlFilter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author Scott
|
||||||
|
* @create 2019-02-01 15:56
|
||||||
|
* @desc 鉴权请求URL访问权限拦截器
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class ResourceCheckFilter extends AccessControlFilter {
|
||||||
|
|
||||||
|
private String errorUrl;
|
||||||
|
|
||||||
|
public String getErrorUrl() {
|
||||||
|
return errorUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setErrorUrl(String errorUrl) {
|
||||||
|
this.errorUrl = errorUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表示是否允许访问 ,如果允许访问返回true,否则false;
|
||||||
|
*
|
||||||
|
* @param servletRequest
|
||||||
|
* @param servletResponse
|
||||||
|
* @param o 表示写在拦截器中括号里面的字符串 mappedValue 就是 [urls] 配置中拦截器参数部分
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {
|
||||||
|
Subject subject = getSubject(servletRequest, servletResponse);
|
||||||
|
String url = getPathWithinApplication(servletRequest);
|
||||||
|
log.info("当前用户正在访问的 url => " + url);
|
||||||
|
return subject.isPermitted(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* onAccessDenied:表示当访问拒绝时是否已经处理了; 如果返回 true 表示需要继续处理; 如果返回 false
|
||||||
|
* 表示该拦截器实例已经处理了,将直接返回即可。
|
||||||
|
*
|
||||||
|
* @param servletRequest
|
||||||
|
* @param servletResponse
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
|
||||||
|
log.info("当 isAccessAllowed 返回 false 的时候,才会执行 method onAccessDenied ");
|
||||||
|
|
||||||
|
HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||||
|
HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||||
|
response.sendRedirect(request.getContextPath() + this.errorUrl);
|
||||||
|
|
||||||
|
// 返回 false 表示已经处理,例如页面跳转啥的,表示不在走以下的拦截器了(如果还有配置的话)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
package org.jeecg.config.sign.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 签名校验注解
|
||||||
|
* 用于方法级别的签名验证,功能等同于yml中的jeecg.signUrls配置
|
||||||
|
* 参考DragSignatureAspect的设计思路,使用AOP切面实现
|
||||||
|
*
|
||||||
|
* @author GitHub Copilot
|
||||||
|
* @since 2025-12-15
|
||||||
|
*/
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface SignatureCheck {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否启用签名校验
|
||||||
|
* @return true-启用(默认), false-禁用
|
||||||
|
*/
|
||||||
|
boolean enabled() default true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 签名校验失败时的错误消息
|
||||||
|
* @return 错误消息
|
||||||
|
*/
|
||||||
|
String errorMessage() default "Sign签名校验失败!";
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,93 @@
|
|||||||
|
package org.jeecg.config.sign.aspect;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Before;
|
||||||
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
|
import org.aspectj.lang.reflect.MethodSignature;
|
||||||
|
import org.jeecg.config.sign.annotation.SignatureCheck;
|
||||||
|
import org.jeecg.config.sign.interceptor.SignAuthInterceptor;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基于AOP的签名验证切面
|
||||||
|
* 复用SignAuthInterceptor的成熟签名验证逻辑
|
||||||
|
*
|
||||||
|
* @author GitHub Copilot
|
||||||
|
* @since 2025-12-15
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Slf4j
|
||||||
|
@Component("signatureCheckAspect")
|
||||||
|
public class SignatureCheckAspect {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复用SignAuthInterceptor的签名验证逻辑
|
||||||
|
*/
|
||||||
|
private final SignAuthInterceptor signAuthInterceptor = new SignAuthInterceptor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验签切点:拦截所有标记了@SignatureCheck注解的方法
|
||||||
|
*/
|
||||||
|
@Pointcut("@annotation(org.jeecg.config.sign.annotation.SignatureCheck)")
|
||||||
|
private void signatureCheckPointCut() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始验签
|
||||||
|
*/
|
||||||
|
@Before("signatureCheckPointCut()")
|
||||||
|
public void doSignatureValidation(JoinPoint point) throws Exception {
|
||||||
|
// 获取方法上的注解
|
||||||
|
MethodSignature signature = (MethodSignature) point.getSignature();
|
||||||
|
Method method = signature.getMethod();
|
||||||
|
SignatureCheck signatureCheck = method.getAnnotation(SignatureCheck.class);
|
||||||
|
|
||||||
|
log.info("AOP签名验证: {}.{}", method.getDeclaringClass().getSimpleName(), method.getName());
|
||||||
|
|
||||||
|
// 如果注解被禁用,直接返回
|
||||||
|
if (!signatureCheck.enabled()) {
|
||||||
|
log.info("签名验证已禁用,跳过");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||||
|
if (attributes == null) {
|
||||||
|
log.error("无法获取请求上下文");
|
||||||
|
throw new IllegalArgumentException("无法获取请求上下文");
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpServletRequest request = attributes.getRequest();
|
||||||
|
log.info("X-SIGN: {}, X-TIMESTAMP: {}", request.getHeader("X-SIGN"), request.getHeader("X-TIMESTAMP"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 直接调用SignAuthInterceptor的验证逻辑
|
||||||
|
signAuthInterceptor.validateSignature(request);
|
||||||
|
log.info("AOP签名验证通过");
|
||||||
|
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// 使用注解中配置的错误消息,或者保留原始错误消息
|
||||||
|
String errorMessage = signatureCheck.errorMessage();
|
||||||
|
log.error("AOP签名验证失败: {}", e.getMessage());
|
||||||
|
|
||||||
|
if ("Sign签名校验失败!".equals(errorMessage)) {
|
||||||
|
// 如果是默认错误消息,使用原始的详细错误信息
|
||||||
|
throw e;
|
||||||
|
} else {
|
||||||
|
// 如果是自定义错误消息,使用自定义消息
|
||||||
|
throw new IllegalArgumentException(errorMessage, e);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 包装其他异常
|
||||||
|
String errorMessage = signatureCheck.errorMessage();
|
||||||
|
log.error("AOP签名验证异常: {}", e.getMessage());
|
||||||
|
throw new IllegalArgumentException(errorMessage, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,12 +1,10 @@
|
|||||||
package org.jeecg.config.sign.interceptor;
|
package org.jeecg.config.sign.interceptor;
|
||||||
|
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import com.alibaba.fastjson.JSON;
|
||||||
import java.util.SortedMap;
|
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.util.DateUtils;
|
import org.jeecg.common.util.DateUtils;
|
||||||
@ -16,9 +14,8 @@ import org.jeecg.config.sign.util.HttpUtils;
|
|||||||
import org.jeecg.config.sign.util.SignUtil;
|
import org.jeecg.config.sign.util.SignUtil;
|
||||||
import org.springframework.web.servlet.HandlerInterceptor;
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import java.io.PrintWriter;
|
||||||
|
import java.util.SortedMap;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 签名拦截器
|
* 签名拦截器
|
||||||
@ -33,63 +30,94 @@ public class SignAuthInterceptor implements HandlerInterceptor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||||
log.debug("Sign Interceptor request URI = " + request.getRequestURI());
|
log.info("签名拦截器 Interceptor request URI = " + request.getRequestURI());
|
||||||
HttpServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(request);
|
|
||||||
//获取全部参数(包括URL和body上的)
|
|
||||||
SortedMap<String, String> allParams = HttpUtils.getAllParams(requestWrapper);
|
|
||||||
//对参数进行签名验证
|
|
||||||
String headerSign = request.getHeader(CommonConstant.X_SIGN);
|
|
||||||
String xTimestamp = request.getHeader(CommonConstant.X_TIMESTAMP);
|
|
||||||
|
|
||||||
if(oConvertUtils.isEmpty(xTimestamp)){
|
try {
|
||||||
Result<?> result = Result.error("Sign签名校验失败,时间戳为空!");
|
// 调用验证逻辑
|
||||||
log.error("Sign 签名校验失败!Header xTimestamp 为空");
|
validateSignature(request);
|
||||||
//校验失败返回前端
|
|
||||||
response.setCharacterEncoding("UTF-8");
|
|
||||||
response.setContentType("application/json; charset=utf-8");
|
|
||||||
PrintWriter out = response.getWriter();
|
|
||||||
out.print(JSON.toJSON(result));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//客户端时间
|
|
||||||
Long clientTimestamp = Long.parseLong(xTimestamp);
|
|
||||||
|
|
||||||
int length = 14;
|
|
||||||
int length1000 = 1000;
|
|
||||||
//1.校验签名时间(兼容X_TIMESTAMP的新老格式)
|
|
||||||
if (xTimestamp.length() == length) {
|
|
||||||
//a. X_TIMESTAMP格式是 yyyyMMddHHmmss (例子:20220308152143)
|
|
||||||
if ((DateUtils.getCurrentTimestamp() - clientTimestamp) > MAX_EXPIRE) {
|
|
||||||
log.error("签名验证失败:X-TIMESTAMP已过期,注意系统时间和服务器时间是否有误差!");
|
|
||||||
throw new IllegalArgumentException("签名验证失败:X-TIMESTAMP已过期");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//b. X_TIMESTAMP格式是 时间戳 (例子:1646552406000)
|
|
||||||
if ((System.currentTimeMillis() - clientTimestamp) > (MAX_EXPIRE * length1000)) {
|
|
||||||
log.error("签名验证失败:X-TIMESTAMP已过期,注意系统时间和服务器时间是否有误差!");
|
|
||||||
throw new IllegalArgumentException("签名验证失败:X-TIMESTAMP已过期");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//2.校验签名
|
|
||||||
boolean isSigned = SignUtil.verifySign(allParams,headerSign);
|
|
||||||
|
|
||||||
if (isSigned) {
|
|
||||||
log.debug("Sign 签名通过!Header Sign : {}",headerSign);
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} catch (IllegalArgumentException e) {
|
||||||
log.debug("sign allParams: {}", allParams);
|
// 验证失败,返回错误响应
|
||||||
log.error("request URI = " + request.getRequestURI());
|
log.error("Sign 签名校验失败!{}", e.getMessage());
|
||||||
log.error("Sign 签名校验失败!Header Sign : {}",headerSign);
|
|
||||||
//校验失败返回前端
|
|
||||||
response.setCharacterEncoding("UTF-8");
|
response.setCharacterEncoding("UTF-8");
|
||||||
response.setContentType("application/json; charset=utf-8");
|
response.setContentType("application/json; charset=utf-8");
|
||||||
PrintWriter out = response.getWriter();
|
PrintWriter out = response.getWriter();
|
||||||
Result<?> result = Result.error("Sign签名校验失败!");
|
Result<?> result = Result.error(e.getMessage());
|
||||||
out.print(JSON.toJSON(result));
|
out.print(JSON.toJSON(result));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 签名验证核心逻辑
|
||||||
|
* 提取出来供AOP切面复用
|
||||||
|
* @param request HTTP请求
|
||||||
|
* @throws IllegalArgumentException 验证失败时抛出异常
|
||||||
|
*/
|
||||||
|
public void validateSignature(HttpServletRequest request) throws IllegalArgumentException {
|
||||||
|
try {
|
||||||
|
log.debug("开始签名验证: {} {}", request.getMethod(), request.getRequestURI());
|
||||||
|
|
||||||
|
HttpServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(request);
|
||||||
|
//获取全部参数(包括URL和body上的)
|
||||||
|
SortedMap<String, String> allParams = HttpUtils.getAllParams(requestWrapper);
|
||||||
|
log.debug("提取参数: {}", allParams);
|
||||||
|
|
||||||
|
//对参数进行签名验证
|
||||||
|
String headerSign = request.getHeader(CommonConstant.X_SIGN);
|
||||||
|
String xTimestamp = request.getHeader(CommonConstant.X_TIMESTAMP);
|
||||||
|
|
||||||
|
if(oConvertUtils.isEmpty(xTimestamp)){
|
||||||
|
log.error("Sign签名校验失败,时间戳为空!");
|
||||||
|
throw new IllegalArgumentException("Sign签名校验失败,请求参数不完整!");
|
||||||
|
}
|
||||||
|
|
||||||
|
//客户端时间
|
||||||
|
Long clientTimestamp = Long.parseLong(xTimestamp);
|
||||||
|
|
||||||
|
int length = 14;
|
||||||
|
int length1000 = 1000;
|
||||||
|
//1.校验签名时间(兼容X_TIMESTAMP的新老格式)
|
||||||
|
if (xTimestamp.length() == length) {
|
||||||
|
//a. X_TIMESTAMP格式是 yyyyMMddHHmmss (例子:20220308152143)
|
||||||
|
long currentTimestamp = DateUtils.getCurrentTimestamp();
|
||||||
|
long timeDiff = currentTimestamp - clientTimestamp;
|
||||||
|
log.debug("时间戳验证(yyyyMMddHHmmss): 时间差{}秒", timeDiff);
|
||||||
|
|
||||||
|
if (timeDiff > MAX_EXPIRE) {
|
||||||
|
log.error("时间戳已过期: {}秒 > {}秒", timeDiff, MAX_EXPIRE);
|
||||||
|
throw new IllegalArgumentException("签名验证失败,请求时效性验证失败!");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//b. X_TIMESTAMP格式是 时间戳 (例子:1646552406000)
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
long timeDiff = currentTime - clientTimestamp;
|
||||||
|
long maxExpireMs = MAX_EXPIRE * length1000;
|
||||||
|
log.debug("时间戳验证(Unix): 时间差{}ms", timeDiff);
|
||||||
|
|
||||||
|
if (timeDiff > maxExpireMs) {
|
||||||
|
log.error("时间戳已过期: {}ms > {}ms", timeDiff, maxExpireMs);
|
||||||
|
throw new IllegalArgumentException("签名验证失败,请求时效性验证失败!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//2.校验签名
|
||||||
|
boolean isSigned = SignUtil.verifySign(allParams,headerSign);
|
||||||
|
|
||||||
|
if (isSigned) {
|
||||||
|
log.debug("签名验证通过");
|
||||||
|
} else {
|
||||||
|
log.error("签名验证失败, 参数: {}", allParams);
|
||||||
|
throw new IllegalArgumentException("Sign签名校验失败!");
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// 重新抛出签名验证异常
|
||||||
|
throw e;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 包装其他异常(如IOException)
|
||||||
|
log.error("签名验证异常: {}", e.getMessage());
|
||||||
|
throw new IllegalArgumentException("Sign签名校验失败:" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,18 @@
|
|||||||
|
package org.jeecg.config.vo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: TODO
|
||||||
|
* @author: scott
|
||||||
|
* @date: 2022年01月21日 14:23
|
||||||
|
*/
|
||||||
|
public class Shiro {
|
||||||
|
private String excludeUrls = "";
|
||||||
|
|
||||||
|
public String getExcludeUrls() {
|
||||||
|
return excludeUrls;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExcludeUrls(String excludeUrls) {
|
||||||
|
this.excludeUrls = excludeUrls;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,10 +2,10 @@ package org.jeecg.modules.base.service.impl;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
import org.jeecg.common.api.dto.LogDTO;
|
import org.jeecg.common.api.dto.LogDTO;
|
||||||
import org.jeecg.common.constant.enums.ClientTerminalTypeEnum;
|
import org.jeecg.common.constant.enums.ClientTerminalTypeEnum;
|
||||||
import org.jeecg.common.util.BrowserUtils;
|
import org.jeecg.common.util.BrowserUtils;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecg.modules.base.mapper.BaseCommonMapper;
|
import org.jeecg.modules.base.mapper.BaseCommonMapper;
|
||||||
import org.jeecg.modules.base.service.BaseCommonService;
|
import org.jeecg.modules.base.service.BaseCommonService;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
@ -35,7 +35,7 @@ public class BaseCommonServiceImpl implements BaseCommonService {
|
|||||||
logDTO.setId(String.valueOf(IdWorker.getId()));
|
logDTO.setId(String.valueOf(IdWorker.getId()));
|
||||||
}
|
}
|
||||||
//保存日志(异常捕获处理,防止数据太大存储失败,导致业务失败)JT-238
|
//保存日志(异常捕获处理,防止数据太大存储失败,导致业务失败)JT-238
|
||||||
try {
|
try {
|
||||||
logDTO.setCreateTime(new Date());
|
logDTO.setCreateTime(new Date());
|
||||||
baseCommonMapper.saveLog(logDTO);
|
baseCommonMapper.saveLog(logDTO);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -74,7 +74,7 @@ public class BaseCommonServiceImpl implements BaseCommonService {
|
|||||||
//获取登录用户信息
|
//获取登录用户信息
|
||||||
if(user==null){
|
if(user==null){
|
||||||
try {
|
try {
|
||||||
user = SecureUtil.currentUser();
|
user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
//e.printStackTrace();
|
//e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.system.base.controller.JeecgController;
|
import org.jeecg.common.system.base.controller.JeecgController;
|
||||||
import org.jeecg.common.system.query.QueryGenerator;
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
@ -17,7 +18,6 @@ import org.jeecg.modules.airag.app.service.IAiragAppService;
|
|||||||
import org.jeecg.modules.airag.app.service.IAiragChatService;
|
import org.jeecg.modules.airag.app.service.IAiragChatService;
|
||||||
import org.jeecg.modules.airag.app.vo.AppDebugParams;
|
import org.jeecg.modules.airag.app.vo.AppDebugParams;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ public class AiragAppController extends JeecgController<AiragApp, IAiragAppServi
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
|
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
|
||||||
@PreAuthorize("@jps.requiresPermissions('airag:app:edit')")
|
@RequiresPermissions("airag:app:edit")
|
||||||
public Result<String> edit(@RequestBody AiragApp airagApp) {
|
public Result<String> edit(@RequestBody AiragApp airagApp) {
|
||||||
AssertUtils.assertNotEmpty("参数异常", airagApp);
|
AssertUtils.assertNotEmpty("参数异常", airagApp);
|
||||||
AssertUtils.assertNotEmpty("请输入应用名称", airagApp.getName());
|
AssertUtils.assertNotEmpty("请输入应用名称", airagApp.getName());
|
||||||
@ -106,7 +106,7 @@ public class AiragAppController extends JeecgController<AiragApp, IAiragAppServi
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
@PreAuthorize("@jps.requiresPermissions('airag:app:delete')")
|
@RequiresPermissions("airag:app:delete")
|
||||||
public Result<String> delete(HttpServletRequest request,@RequestParam(name = "id", required = true) String id) {
|
public Result<String> delete(HttpServletRequest request,@RequestParam(name = "id", required = true) String id) {
|
||||||
//update-begin---author:chenrui ---date:20250606 for:[issues/8337]关于ai工作列表的数据权限问题 #8337------------
|
//update-begin---author:chenrui ---date:20250606 for:[issues/8337]关于ai工作列表的数据权限问题 #8337------------
|
||||||
//如果是saas隔离的情况下,判断当前租户id是否是当前租户下的
|
//如果是saas隔离的情况下,判断当前租户id是否是当前租户下的
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.system.query.QueryGenerator;
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
import org.jeecg.common.util.AssertUtils;
|
import org.jeecg.common.util.AssertUtils;
|
||||||
@ -17,7 +18,6 @@ import org.jeecg.modules.airag.llm.handler.EmbeddingHandler;
|
|||||||
import org.jeecg.modules.airag.llm.service.IAiragKnowledgeDocService;
|
import org.jeecg.modules.airag.llm.service.IAiragKnowledgeDocService;
|
||||||
import org.jeecg.modules.airag.llm.service.IAiragKnowledgeService;
|
import org.jeecg.modules.airag.llm.service.IAiragKnowledgeService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
@ -77,7 +77,7 @@ public class AiragKnowledgeController {
|
|||||||
* @date 2025/2/18 17:09
|
* @date 2025/2/18 17:09
|
||||||
*/
|
*/
|
||||||
@PostMapping(value = "/add")
|
@PostMapping(value = "/add")
|
||||||
@PreAuthorize("@jps.requiresPermissions('airag:knowledge:add')")
|
@RequiresPermissions("airag:knowledge:add")
|
||||||
public Result<String> add(@RequestBody AiragKnowledge airagKnowledge) {
|
public Result<String> add(@RequestBody AiragKnowledge airagKnowledge) {
|
||||||
airagKnowledge.setStatus(LLMConsts.STATUS_ENABLE);
|
airagKnowledge.setStatus(LLMConsts.STATUS_ENABLE);
|
||||||
airagKnowledgeService.save(airagKnowledge);
|
airagKnowledgeService.save(airagKnowledge);
|
||||||
@ -94,7 +94,7 @@ public class AiragKnowledgeController {
|
|||||||
*/
|
*/
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
|
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
|
||||||
@PreAuthorize("@jps.requiresPermissions('airag:knowledge:edit')")
|
@RequiresPermissions("airag:knowledge:edit")
|
||||||
public Result<String> edit(@RequestBody AiragKnowledge airagKnowledge) {
|
public Result<String> edit(@RequestBody AiragKnowledge airagKnowledge) {
|
||||||
AiragKnowledge airagKnowledgeEntity = airagKnowledgeService.getById(airagKnowledge.getId());
|
AiragKnowledge airagKnowledgeEntity = airagKnowledgeService.getById(airagKnowledge.getId());
|
||||||
if (airagKnowledgeEntity == null) {
|
if (airagKnowledgeEntity == null) {
|
||||||
@ -118,7 +118,7 @@ public class AiragKnowledgeController {
|
|||||||
* @date 2025/3/12 17:05
|
* @date 2025/3/12 17:05
|
||||||
*/
|
*/
|
||||||
@PutMapping(value = "/rebuild")
|
@PutMapping(value = "/rebuild")
|
||||||
@PreAuthorize("@jps.requiresPermissions('airag:knowledge:rebuild')")
|
@RequiresPermissions("airag:knowledge:rebuild")
|
||||||
public Result<?> rebuild(@RequestParam("knowIds") String knowIds) {
|
public Result<?> rebuild(@RequestParam("knowIds") String knowIds) {
|
||||||
String[] knowIdArr = knowIds.split(",");
|
String[] knowIdArr = knowIds.split(",");
|
||||||
for (String knowId : knowIdArr) {
|
for (String knowId : knowIdArr) {
|
||||||
@ -137,7 +137,7 @@ public class AiragKnowledgeController {
|
|||||||
*/
|
*/
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
@PreAuthorize("@jps.requiresPermissions('airag:knowledge:delete')")
|
@RequiresPermissions("airag:knowledge:delete")
|
||||||
public Result<String> delete(HttpServletRequest request, @RequestParam(name = "id", required = true) String id) {
|
public Result<String> delete(HttpServletRequest request, @RequestParam(name = "id", required = true) String id) {
|
||||||
//update-begin---author:chenrui ---date:20250606 for:[issues/8337]关于ai工作列表的数据权限问题 #8337------------
|
//update-begin---author:chenrui ---date:20250606 for:[issues/8337]关于ai工作列表的数据权限问题 #8337------------
|
||||||
//如果是saas隔离的情况下,判断当前租户id是否是当前租户下的
|
//如果是saas隔离的情况下,判断当前租户id是否是当前租户下的
|
||||||
@ -204,7 +204,7 @@ public class AiragKnowledgeController {
|
|||||||
* @date 2025/2/18 15:47
|
* @date 2025/2/18 15:47
|
||||||
*/
|
*/
|
||||||
@PostMapping(value = "/doc/edit")
|
@PostMapping(value = "/doc/edit")
|
||||||
@PreAuthorize("@jps.requiresPermissions('airag:knowledge:doc:edit')")
|
@RequiresPermissions("airag:knowledge:doc:edit")
|
||||||
public Result<?> addDocument(@RequestBody AiragKnowledgeDoc airagKnowledgeDoc) {
|
public Result<?> addDocument(@RequestBody AiragKnowledgeDoc airagKnowledgeDoc) {
|
||||||
return airagKnowledgeDocService.editDocument(airagKnowledgeDoc);
|
return airagKnowledgeDocService.editDocument(airagKnowledgeDoc);
|
||||||
}
|
}
|
||||||
@ -217,7 +217,7 @@ public class AiragKnowledgeController {
|
|||||||
* @date 2025/3/20 11:29
|
* @date 2025/3/20 11:29
|
||||||
*/
|
*/
|
||||||
@PostMapping(value = "/doc/import/zip")
|
@PostMapping(value = "/doc/import/zip")
|
||||||
@PreAuthorize("@jps.requiresPermissions('airag:knowledge:doc:zip')")
|
@RequiresPermissions("airag:knowledge:doc:zip")
|
||||||
public Result<?> importDocumentFromZip(@RequestParam(name = "knowId", required = true) String knowId,
|
public Result<?> importDocumentFromZip(@RequestParam(name = "knowId", required = true) String knowId,
|
||||||
@RequestParam(name = "file", required = true) MultipartFile file) {
|
@RequestParam(name = "file", required = true) MultipartFile file) {
|
||||||
return airagKnowledgeDocService.importDocumentFromZip(knowId,file);
|
return airagKnowledgeDocService.importDocumentFromZip(knowId,file);
|
||||||
@ -244,7 +244,7 @@ public class AiragKnowledgeController {
|
|||||||
* @date 2025/2/18 15:47
|
* @date 2025/2/18 15:47
|
||||||
*/
|
*/
|
||||||
@PutMapping(value = "/doc/rebuild")
|
@PutMapping(value = "/doc/rebuild")
|
||||||
@PreAuthorize("@jps.requiresPermissions('airag:knowledge:doc:rebuild')")
|
@RequiresPermissions("airag:knowledge:doc:rebuild")
|
||||||
public Result<?> rebuildDocument(@RequestParam("docIds") String docIds) {
|
public Result<?> rebuildDocument(@RequestParam("docIds") String docIds) {
|
||||||
return airagKnowledgeDocService.rebuildDocument(docIds);
|
return airagKnowledgeDocService.rebuildDocument(docIds);
|
||||||
}
|
}
|
||||||
@ -259,7 +259,7 @@ public class AiragKnowledgeController {
|
|||||||
*/
|
*/
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@DeleteMapping(value = "/doc/deleteBatch")
|
@DeleteMapping(value = "/doc/deleteBatch")
|
||||||
@PreAuthorize("@jps.requiresPermissions('airag:knowledge:doc:deleteBatch')")
|
@RequiresPermissions("airag:knowledge:doc:deleteBatch")
|
||||||
public Result<String> deleteDocumentBatch(HttpServletRequest request, @RequestParam(name = "ids", required = true) String ids) {
|
public Result<String> deleteDocumentBatch(HttpServletRequest request, @RequestParam(name = "ids", required = true) String ids) {
|
||||||
List<String> idsList = Arrays.asList(ids.split(","));
|
List<String> idsList = Arrays.asList(ids.split(","));
|
||||||
//update-begin---author:chenrui ---date:20250606 for:[issues/8337]关于ai工作列表的数据权限问题 #8337------------
|
//update-begin---author:chenrui ---date:20250606 for:[issues/8337]关于ai工作列表的数据权限问题 #8337------------
|
||||||
@ -287,7 +287,7 @@ public class AiragKnowledgeController {
|
|||||||
*/
|
*/
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@DeleteMapping(value = "/doc/deleteAll")
|
@DeleteMapping(value = "/doc/deleteAll")
|
||||||
@PreAuthorize("@jps.requiresPermissions('airag:knowledge:doc:deleteAll')")
|
@RequiresPermissions("airag:knowledge:doc:deleteAll")
|
||||||
public Result<?> deleteDocumentAll(HttpServletRequest request, @RequestParam(name = "knowId") String knowId) {
|
public Result<?> deleteDocumentAll(HttpServletRequest request, @RequestParam(name = "knowId") String knowId) {
|
||||||
//update-begin---author:chenrui ---date:20250606 for:[issues/8337]关于ai工作列表的数据权限问题 #8337------------
|
//update-begin---author:chenrui ---date:20250606 for:[issues/8337]关于ai工作列表的数据权限问题 #8337------------
|
||||||
//如果是saas隔离的情况下,判断当前租户id是否是当前租户下的
|
//如果是saas隔离的情况下,判断当前租户id是否是当前租户下的
|
||||||
|
|||||||
@ -169,7 +169,7 @@ public class AiragMcpController extends JeecgController<AiragMcp, IAiragMcpServi
|
|||||||
* @param request
|
* @param request
|
||||||
* @param airagMcp
|
* @param airagMcp
|
||||||
*/
|
*/
|
||||||
// @PreAuthorize("@jps.requiresPermissions('llm:airag_mcp:exportXls")
|
// @RequiresPermissions("llm:airag_mcp:exportXls")
|
||||||
@RequestMapping(value = "/exportXls")
|
@RequestMapping(value = "/exportXls")
|
||||||
public ModelAndView exportXls(HttpServletRequest request, AiragMcp airagMcp) {
|
public ModelAndView exportXls(HttpServletRequest request, AiragMcp airagMcp) {
|
||||||
return super.exportXls(request, airagMcp, AiragMcp.class, "MCP");
|
return super.exportXls(request, airagMcp, AiragMcp.class, "MCP");
|
||||||
@ -182,7 +182,7 @@ public class AiragMcpController extends JeecgController<AiragMcp, IAiragMcpServi
|
|||||||
* @param response
|
* @param response
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
// @PreAuthorize("@jps.requiresPermissions('llm:airag_mcp:importExcel")
|
// @RequiresPermissions("llm:airag_mcp:importExcel")
|
||||||
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
|
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
|
||||||
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
|
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
|
||||||
return super.importExcel(request, response, AiragMcp.class);
|
return super.importExcel(request, response, AiragMcp.class);
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import dev.langchain4j.data.message.UserMessage;
|
|||||||
import dev.langchain4j.model.embedding.EmbeddingModel;
|
import dev.langchain4j.model.embedding.EmbeddingModel;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
import org.jeecg.ai.factory.AiModelFactory;
|
import org.jeecg.ai.factory.AiModelFactory;
|
||||||
import org.jeecg.ai.factory.AiModelOptions;
|
import org.jeecg.ai.factory.AiModelOptions;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
@ -22,7 +23,6 @@ import org.jeecg.modules.airag.llm.handler.AIChatHandler;
|
|||||||
import org.jeecg.modules.airag.llm.handler.EmbeddingHandler;
|
import org.jeecg.modules.airag.llm.handler.EmbeddingHandler;
|
||||||
import org.jeecg.modules.airag.llm.service.IAiragModelService;
|
import org.jeecg.modules.airag.llm.service.IAiragModelService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ public class AiragModelController extends JeecgController<AiragModel, IAiragMode
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PostMapping(value = "/add")
|
@PostMapping(value = "/add")
|
||||||
@PreAuthorize("@jps.requiresPermissions('airag:model:add')")
|
@RequiresPermissions("airag:model:add")
|
||||||
public Result<String> add(@RequestBody AiragModel airagModel) {
|
public Result<String> add(@RequestBody AiragModel airagModel) {
|
||||||
// 验证 模型名称/模型类型/基础模型
|
// 验证 模型名称/模型类型/基础模型
|
||||||
AssertUtils.assertNotEmpty("模型名称不能为空", airagModel.getName());
|
AssertUtils.assertNotEmpty("模型名称不能为空", airagModel.getName());
|
||||||
@ -95,7 +95,7 @@ public class AiragModelController extends JeecgController<AiragModel, IAiragMode
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
|
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
|
||||||
@PreAuthorize("@jps.requiresPermissions('airag:model:edit')")
|
@RequiresPermissions("airag:model:edit")
|
||||||
public Result<String> edit(@RequestBody AiragModel airagModel) {
|
public Result<String> edit(@RequestBody AiragModel airagModel) {
|
||||||
airagModelService.updateById(airagModel);
|
airagModelService.updateById(airagModel);
|
||||||
return Result.OK("编辑成功!");
|
return Result.OK("编辑成功!");
|
||||||
@ -108,7 +108,7 @@ public class AiragModelController extends JeecgController<AiragModel, IAiragMode
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
@PreAuthorize("@jps.requiresPermissions('airag:model:delete')")
|
@RequiresPermissions("airag:model:delete")
|
||||||
public Result<String> delete(HttpServletRequest request, @RequestParam(name = "id", required = true) String id) {
|
public Result<String> delete(HttpServletRequest request, @RequestParam(name = "id", required = true) String id) {
|
||||||
//update-begin---author:chenrui ---date:20250606 for:[issues/8337]关于ai工作列表的数据权限问题 #8337------------
|
//update-begin---author:chenrui ---date:20250606 for:[issues/8337]关于ai工作列表的数据权限问题 #8337------------
|
||||||
//如果是saas隔离的情况下,判断当前租户id是否是当前租户下的
|
//如果是saas隔离的情况下,判断当前租户id是否是当前租户下的
|
||||||
|
|||||||
@ -10,6 +10,8 @@ import io.swagger.v3.oas.annotations.Operation;
|
|||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.mgt.DefaultSecurityManager;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.aspect.annotation.AutoLog;
|
import org.jeecg.common.aspect.annotation.AutoLog;
|
||||||
import org.jeecg.common.aspect.annotation.PermissionData;
|
import org.jeecg.common.aspect.annotation.PermissionData;
|
||||||
@ -473,13 +475,12 @@ public class JeecgDemoController extends JeecgController<JeecgDemo, IJeecgDemoSe
|
|||||||
* 测试Mono对象
|
* 测试Mono对象
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Operation(summary = "Mono测试")
|
|
||||||
@GetMapping(value ="/test")
|
@GetMapping(value ="/test")
|
||||||
public Mono<String> test() {
|
public Mono<String> test() {
|
||||||
//解决shiro报错No SecurityManager accessible to the calling code, either bound to the org.apache.shiro
|
//解决shiro报错No SecurityManager accessible to the calling code, either bound to the org.apache.shiro
|
||||||
// https://blog.csdn.net/Japhet_jiu/article/details/131177210
|
// https://blog.csdn.net/Japhet_jiu/article/details/131177210
|
||||||
// DefaultSecurityManager securityManager = new DefaultSecurityManager();
|
DefaultSecurityManager securityManager = new DefaultSecurityManager();
|
||||||
// SecurityUtils.setSecurityManager(securityManager);
|
SecurityUtils.setSecurityManager(securityManager);
|
||||||
|
|
||||||
return Mono.just("测试");
|
return Mono.just("测试");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,16 +5,15 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.system.base.controller.JeecgController;
|
import org.jeecg.common.system.base.controller.JeecgController;
|
||||||
import org.jeecg.common.system.query.QueryGenerator;
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecg.modules.demo.test.entity.JeecgDemo;
|
import org.jeecg.modules.demo.test.entity.JeecgDemo;
|
||||||
import org.jeecg.modules.demo.test.entity.JeecgOrderCustomer;
|
import org.jeecg.modules.demo.test.entity.JeecgOrderCustomer;
|
||||||
import org.jeecg.modules.demo.test.entity.JeecgOrderMain;
|
import org.jeecg.modules.demo.test.entity.JeecgOrderMain;
|
||||||
@ -31,7 +30,6 @@ import org.jeecgframework.poi.excel.entity.ImportParams;
|
|||||||
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
|
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -186,7 +184,7 @@ public class JeecgOrderMainController extends JeecgController<JeecgOrderMain, IJ
|
|||||||
//Step.2 AutoPoi 导出Excel
|
//Step.2 AutoPoi 导出Excel
|
||||||
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
|
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
|
||||||
//获取当前用户
|
//获取当前用户
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
|
|
||||||
List<JeecgOrderMainPage> pageList = new ArrayList<JeecgOrderMainPage>();
|
List<JeecgOrderMainPage> pageList = new ArrayList<JeecgOrderMainPage>();
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,17 @@
|
|||||||
package org.jeecg.modules.demo.test.service.impl;
|
package org.jeecg.modules.demo.test.service.impl;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
import org.jeecg.common.constant.CacheConstant;
|
import org.jeecg.common.constant.CacheConstant;
|
||||||
import org.jeecg.common.system.query.QueryGenerator;
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecg.modules.demo.test.entity.JeecgDemo;
|
import org.jeecg.modules.demo.test.entity.JeecgDemo;
|
||||||
import org.jeecg.modules.demo.test.mapper.JeecgDemoMapper;
|
import org.jeecg.modules.demo.test.mapper.JeecgDemoMapper;
|
||||||
import org.jeecg.modules.demo.test.service.IJeecgDemoService;
|
import org.jeecg.modules.demo.test.service.IJeecgDemoService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.cache.annotation.Cacheable;
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@ -99,7 +97,7 @@ public class JeecgDemoServiceImpl extends ServiceImpl<JeecgDemoMapper, JeecgDemo
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getExportFields() {
|
public String getExportFields() {
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
//权限配置列导出示例
|
//权限配置列导出示例
|
||||||
//1.配置前缀与菜单中配置的列前缀一致
|
//1.配置前缀与菜单中配置的列前缀一致
|
||||||
List<String> noAuthList = new ArrayList<>();
|
List<String> noAuthList = new ArrayList<>();
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import org.jeecg.common.system.api.factory.SysBaseAPIFallbackFactory;
|
|||||||
import org.jeecg.common.system.vo.*;
|
import org.jeecg.common.system.vo.*;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
@ -898,20 +899,4 @@ public interface ISysBaseAPI extends CommonAPI {
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/sys/api/uniPushMsgToUser")
|
@PostMapping("/sys/api/uniPushMsgToUser")
|
||||||
void uniPushMsgToUser(@RequestBody PushMessageDTO pushMessageDTO);
|
void uniPushMsgToUser(@RequestBody PushMessageDTO pushMessageDTO);
|
||||||
|
|
||||||
@GetMapping("/sys/api/getUserByPhone")
|
|
||||||
public LoginUser getUserByPhone(@RequestParam("phone") String phone);
|
|
||||||
|
|
||||||
@GetMapping("/sys/api/queryAllDictItems")
|
|
||||||
Map<String,List<DictModel>> queryAllDictItems();
|
|
||||||
|
|
||||||
@GetMapping("/sys/api/queryUserDeparts")
|
|
||||||
List<SysDepartModel> queryUserDeparts(@RequestParam("userId") String userId);
|
|
||||||
|
|
||||||
@PostMapping("/sys/api/updateUserDepart")
|
|
||||||
void updateUserDepart(@RequestParam("username") String username,@RequestParam("orgCode") String orgCode,@RequestParam("loginTenantId") Integer loginTenantId);
|
|
||||||
|
|
||||||
@GetMapping("/sys/api/setLoginTenant")
|
|
||||||
JSONObject setLoginTenant(@RequestParam("username") String username);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -520,30 +520,4 @@ public class SysBaseAPIFallback implements ISysBaseAPI {
|
|||||||
public List<String> queryUserIdsByCascadeDeptIds(List<String> deptIds) {
|
public List<String> queryUserIdsByCascadeDeptIds(List<String> deptIds) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public LoginUser getUserByPhone(String phone) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, List<DictModel>> queryAllDictItems() {
|
|
||||||
return Map.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<SysDepartModel> queryUserDeparts(String userId) {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateUserDepart(String username, String orgCode, Integer loginTenantId) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JSONObject setLoginTenant(String username) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
package org.jeecg.modules.aop;
|
package org.jeecg.modules.aop;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import org.apache.shiro.SecurityUtils;
|
||||||
import org.aspectj.lang.ProceedingJoinPoint;
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
import org.aspectj.lang.annotation.AfterThrowing;
|
import org.aspectj.lang.annotation.AfterThrowing;
|
||||||
import org.aspectj.lang.annotation.Around;
|
import org.aspectj.lang.annotation.Around;
|
||||||
@ -10,11 +10,9 @@ import org.aspectj.lang.reflect.MethodSignature;
|
|||||||
import org.jeecg.common.api.dto.LogDTO;
|
import org.jeecg.common.api.dto.LogDTO;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecg.modules.base.service.BaseCommonService;
|
import org.jeecg.modules.base.service.BaseCommonService;
|
||||||
import org.jeecg.modules.system.entity.SysTenantPack;
|
import org.jeecg.modules.system.entity.SysTenantPack;
|
||||||
import org.jeecg.modules.system.entity.SysTenantPackUser;
|
import org.jeecg.modules.system.entity.SysTenantPackUser;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
@ -81,7 +79,7 @@ public class TenantPackUserLogAspect {
|
|||||||
dto.setOperateType(opType);
|
dto.setOperateType(opType);
|
||||||
dto.setTenantId(tenantId);
|
dto.setTenantId(tenantId);
|
||||||
//获取登录用户信息
|
//获取登录用户信息
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
if(sysUser!=null){
|
if(sysUser!=null){
|
||||||
dto.setUserid(sysUser.getUsername());
|
dto.setUserid(sysUser.getUsername());
|
||||||
dto.setUsername(sysUser.getRealname());
|
dto.setUsername(sysUser.getRealname());
|
||||||
|
|||||||
@ -1044,31 +1044,6 @@ public class SystemApiController {
|
|||||||
sysBaseApi.announcementAutoRelease(dataId, currentUserName);
|
sysBaseApi.announcementAutoRelease(dataId, currentUserName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/sys/api/getUserByPhone")
|
|
||||||
public LoginUser getUserByPhone(String phone) {
|
|
||||||
return sysBaseApi.getUserByPhone(phone);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/sys/api/queryAllDictItems")
|
|
||||||
public Map<String,List<DictModel>> queryAllDictItems() {
|
|
||||||
return sysBaseApi.queryAllDictItems();
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/sys/api/queryUserDeparts")
|
|
||||||
public List<SysDepartModel> queryUserDeparts(@RequestParam("userId") String userId) {
|
|
||||||
return sysBaseApi.queryUserDeparts(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/sys/api/updateUserDepart")
|
|
||||||
public void updateUserDepart(@RequestParam("username") String username,@RequestParam("orgCode") String orgCode,@RequestParam("loginTenantId") Integer loginTenantId) {
|
|
||||||
sysBaseApi.updateUserDepart(username, orgCode, loginTenantId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/sys/api/setLoginTenant")
|
|
||||||
public JSONObject setLoginTenant(@RequestParam("username") String username) {
|
|
||||||
return sysBaseApi.setLoginTenant(username);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据部门编码查询公司信息
|
* 根据部门编码查询公司信息
|
||||||
* @param orgCode 部门编码
|
* @param orgCode 部门编码
|
||||||
@ -1126,7 +1101,6 @@ public class SystemApiController {
|
|||||||
public List<String> queryUserIdsByCascadeDeptIds(@RequestParam("deptIds") List<String> deptIds){
|
public List<String> queryUserIdsByCascadeDeptIds(@RequestParam("deptIds") List<String> deptIds){
|
||||||
return sysBaseApi.queryUserIdsByCascadeDeptIds(deptIds);
|
return sysBaseApi.queryUserIdsByCascadeDeptIds(deptIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 推送uniapp 消息
|
* 推送uniapp 消息
|
||||||
* @param pushMessageDTO
|
* @param pushMessageDTO
|
||||||
|
|||||||
@ -2,12 +2,13 @@ package org.jeecg.modules.oss.controller;
|
|||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.system.query.QueryGenerator;
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
import org.jeecg.modules.oss.entity.OssFile;
|
import org.jeecg.modules.oss.entity.OssFile;
|
||||||
import org.jeecg.modules.oss.service.IOssFileService;
|
import org.jeecg.modules.oss.service.IOssFileService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
@ -47,7 +48,7 @@ public class OssFileController {
|
|||||||
@ResponseBody
|
@ResponseBody
|
||||||
@PostMapping("/upload")
|
@PostMapping("/upload")
|
||||||
//@RequiresRoles("admin")
|
//@RequiresRoles("admin")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:ossFile:upload')")
|
@RequiresPermissions("system:ossFile:upload")
|
||||||
public Result upload(@RequestParam("file") MultipartFile multipartFile) {
|
public Result upload(@RequestParam("file") MultipartFile multipartFile) {
|
||||||
Result result = new Result();
|
Result result = new Result();
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
package org.jeecg.modules.quartz.controller;
|
package org.jeecg.modules.quartz.controller;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.constant.SymbolConstant;
|
import org.jeecg.common.constant.SymbolConstant;
|
||||||
@ -14,7 +16,6 @@ import org.jeecg.common.system.query.QueryGenerator;
|
|||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import org.jeecg.common.util.ImportExcelUtil;
|
import org.jeecg.common.util.ImportExcelUtil;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecg.modules.quartz.entity.QuartzJob;
|
import org.jeecg.modules.quartz.entity.QuartzJob;
|
||||||
import org.jeecg.modules.quartz.service.IQuartzJobService;
|
import org.jeecg.modules.quartz.service.IQuartzJobService;
|
||||||
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
||||||
@ -25,8 +26,6 @@ import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
|
|||||||
import org.quartz.Scheduler;
|
import org.quartz.Scheduler;
|
||||||
import org.quartz.SchedulerException;
|
import org.quartz.SchedulerException;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||||
@ -82,7 +81,7 @@ public class QuartzJobController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
//@RequiresRoles("admin")
|
//@RequiresRoles("admin")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:quartzJob:add')")
|
@RequiresPermissions("system:quartzJob:add")
|
||||||
@RequestMapping(value = "/add", method = RequestMethod.POST)
|
@RequestMapping(value = "/add", method = RequestMethod.POST)
|
||||||
public Result<?> add(@RequestBody QuartzJob quartzJob) {
|
public Result<?> add(@RequestBody QuartzJob quartzJob) {
|
||||||
quartzJobService.saveAndScheduleJob(quartzJob);
|
quartzJobService.saveAndScheduleJob(quartzJob);
|
||||||
@ -96,7 +95,7 @@ public class QuartzJobController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
//@RequiresRoles("admin")
|
//@RequiresRoles("admin")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:quartzJob:edit')")
|
@RequiresPermissions("system:quartzJob:edit")
|
||||||
@RequestMapping(value = "/edit", method ={RequestMethod.PUT, RequestMethod.POST})
|
@RequestMapping(value = "/edit", method ={RequestMethod.PUT, RequestMethod.POST})
|
||||||
public Result<?> eidt(@RequestBody QuartzJob quartzJob) {
|
public Result<?> eidt(@RequestBody QuartzJob quartzJob) {
|
||||||
try {
|
try {
|
||||||
@ -115,7 +114,7 @@ public class QuartzJobController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
//@RequiresRoles("admin")
|
//@RequiresRoles("admin")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:quartzJob:delete')")
|
@RequiresPermissions("system:quartzJob:delete")
|
||||||
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
|
||||||
public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
|
public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
|
||||||
QuartzJob quartzJob = quartzJobService.getById(id);
|
QuartzJob quartzJob = quartzJobService.getById(id);
|
||||||
@ -134,7 +133,7 @@ public class QuartzJobController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
//@RequiresRoles("admin")
|
//@RequiresRoles("admin")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:quartzJob:deleteBatch')")
|
@RequiresPermissions("system:quartzJob:deleteBatch")
|
||||||
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
|
||||||
public Result<?> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
public Result<?> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
||||||
if (ids == null || "".equals(ids.trim())) {
|
if (ids == null || "".equals(ids.trim())) {
|
||||||
@ -154,7 +153,7 @@ public class QuartzJobController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
//@RequiresRoles("admin")
|
//@RequiresRoles("admin")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:quartzJob:pause')")
|
@RequiresPermissions("system:quartzJob:pause")
|
||||||
@GetMapping(value = "/pause")
|
@GetMapping(value = "/pause")
|
||||||
@Operation(summary = "停止定时任务")
|
@Operation(summary = "停止定时任务")
|
||||||
public Result<Object> pauseJob(@RequestParam(name = "id") String id) {
|
public Result<Object> pauseJob(@RequestParam(name = "id") String id) {
|
||||||
@ -173,7 +172,7 @@ public class QuartzJobController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
//@RequiresRoles("admin")
|
//@RequiresRoles("admin")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:quartzJob:resume')")
|
@RequiresPermissions("system:quartzJob:resume")
|
||||||
@GetMapping(value = "/resume")
|
@GetMapping(value = "/resume")
|
||||||
@Operation(summary = "启动定时任务")
|
@Operation(summary = "启动定时任务")
|
||||||
public Result<Object> resumeJob(@RequestParam(name = "id") String id) {
|
public Result<Object> resumeJob(@RequestParam(name = "id") String id) {
|
||||||
@ -221,7 +220,7 @@ public class QuartzJobController {
|
|||||||
mv.addObject(NormalExcelConstants.FILE_NAME, "定时任务列表");
|
mv.addObject(NormalExcelConstants.FILE_NAME, "定时任务列表");
|
||||||
mv.addObject(NormalExcelConstants.CLASS, QuartzJob.class);
|
mv.addObject(NormalExcelConstants.CLASS, QuartzJob.class);
|
||||||
//获取当前登录用户
|
//获取当前登录用户
|
||||||
LoginUser user = SecureUtil.currentUser();
|
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("定时任务列表数据", "导出人:"+user.getRealname(), "导出信息"));
|
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("定时任务列表数据", "导出人:"+user.getRealname(), "导出信息"));
|
||||||
mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
|
mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
|
||||||
return mv;
|
return mv;
|
||||||
@ -278,7 +277,7 @@ public class QuartzJobController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
//@RequiresRoles("admin")
|
//@RequiresRoles("admin")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:quartzJob:execute')")
|
@RequiresPermissions("system:quartzJob:execute")
|
||||||
@GetMapping("/execute")
|
@GetMapping("/execute")
|
||||||
public Result<?> execute(@RequestParam(name = "id", required = true) String id) {
|
public Result<?> execute(@RequestParam(name = "id", required = true) String id) {
|
||||||
QuartzJob quartzJob = quartzJobService.getById(id);
|
QuartzJob quartzJob = quartzJobService.getById(id);
|
||||||
|
|||||||
@ -5,11 +5,15 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.constant.SymbolConstant;
|
import org.jeecg.common.constant.SymbolConstant;
|
||||||
|
import org.jeecg.common.constant.enums.FileTypeEnum;
|
||||||
|
import org.jeecg.common.exception.JeecgBootException;
|
||||||
import org.jeecg.common.util.CommonUtils;
|
import org.jeecg.common.util.CommonUtils;
|
||||||
import org.jeecg.common.util.filter.SsrfFileTypeFilter;
|
import org.jeecg.common.util.filter.SsrfFileTypeFilter;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.modules.system.util.HttpFileToMultipartFileUtil;
|
import org.jeecg.modules.system.util.HttpFileToMultipartFileUtil;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.util.AntPathMatcher;
|
import org.springframework.util.AntPathMatcher;
|
||||||
import org.springframework.util.FileCopyUtils;
|
import org.springframework.util.FileCopyUtils;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@ -79,6 +83,13 @@ public class CommonController {
|
|||||||
savePath = CommonUtils.upload(file, bizPath, uploadType);
|
savePath = CommonUtils.upload(file, bizPath, uploadType);
|
||||||
}
|
}
|
||||||
if(oConvertUtils.isNotEmpty(savePath)){
|
if(oConvertUtils.isNotEmpty(savePath)){
|
||||||
|
|
||||||
|
//添加到文件表
|
||||||
|
String orgName = file.getOriginalFilename();
|
||||||
|
// 获取文件名
|
||||||
|
orgName = CommonUtils.getFileName(orgName);
|
||||||
|
String type = orgName.substring(orgName.lastIndexOf(SymbolConstant.SPOT));
|
||||||
|
FileTypeEnum fileType = FileTypeEnum.getByType(type);
|
||||||
result.setMessage(savePath);
|
result.setMessage(savePath);
|
||||||
result.setSuccess(true);
|
result.setSuccess(true);
|
||||||
}else {
|
}else {
|
||||||
|
|||||||
@ -1,17 +1,18 @@
|
|||||||
package org.jeecg.modules.system.controller;
|
package org.jeecg.modules.system.controller;
|
||||||
|
|
||||||
import cn.hutool.core.util.RandomUtil;
|
import cn.hutool.core.util.RandomUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.aliyuncs.exceptions.ClientException;
|
import com.aliyuncs.exceptions.ClientException;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.constant.CacheConstant;
|
import org.jeecg.common.constant.CacheConstant;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
@ -23,7 +24,6 @@ import org.jeecg.common.util.*;
|
|||||||
import org.jeecg.common.util.encryption.AesEncryptUtil;
|
import org.jeecg.common.util.encryption.AesEncryptUtil;
|
||||||
import org.jeecg.common.util.encryption.EncryptedString;
|
import org.jeecg.common.util.encryption.EncryptedString;
|
||||||
import org.jeecg.config.JeecgBaseConfig;
|
import org.jeecg.config.JeecgBaseConfig;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecg.config.shiro.IgnoreAuth;
|
import org.jeecg.config.shiro.IgnoreAuth;
|
||||||
import org.jeecg.modules.base.service.BaseCommonService;
|
import org.jeecg.modules.base.service.BaseCommonService;
|
||||||
import org.jeecg.modules.system.entity.SysDepart;
|
import org.jeecg.modules.system.entity.SysDepart;
|
||||||
@ -35,27 +35,13 @@ import org.jeecg.modules.system.service.impl.SysBaseApiImpl;
|
|||||||
import org.jeecg.modules.system.util.RandImageUtil;
|
import org.jeecg.modules.system.util.RandImageUtil;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.cache.CacheManager;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.authentication.event.LogoutSuccessEvent;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
|
|
||||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.SynchronousQueue;
|
import java.util.concurrent.SynchronousQueue;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author scott
|
* @Author scott
|
||||||
@ -84,23 +70,15 @@ public class LoginController {
|
|||||||
private BaseCommonService baseCommonService;
|
private BaseCommonService baseCommonService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private JeecgBaseConfig jeecgBaseConfig;
|
private JeecgBaseConfig jeecgBaseConfig;
|
||||||
@Autowired
|
|
||||||
private OAuth2AuthorizationService authorizationService;
|
|
||||||
@Autowired
|
|
||||||
private CacheManager cacheManager;
|
|
||||||
|
|
||||||
private final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";
|
private final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";
|
||||||
/**
|
/**
|
||||||
* 线程池用于异步发送纪要
|
* 线程池用于异步发送纪要
|
||||||
*/
|
*/
|
||||||
public static ExecutorService cachedThreadPool = new ShiroThreadPoolExecutor(0, 1024, 60L, TimeUnit.SECONDS, new SynchronousQueue<>());
|
public static ExecutorService cachedThreadPool = new ShiroThreadPoolExecutor(0, 1024, 60L, TimeUnit.SECONDS, new SynchronousQueue<>());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用spring authorization server提供的各类登录接口
|
|
||||||
* @param sysLoginModel
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Operation(summary="登录接口")
|
@Operation(summary="登录接口")
|
||||||
@RequestMapping(value = "/login", method = RequestMethod.POST)
|
@RequestMapping(value = "/login", method = RequestMethod.POST)
|
||||||
public Result<JSONObject> login(@RequestBody SysLoginModel sysLoginModel, HttpServletRequest request){
|
public Result<JSONObject> login(@RequestBody SysLoginModel sysLoginModel, HttpServletRequest request){
|
||||||
@ -211,12 +189,8 @@ public class LoginController {
|
|||||||
LoginUser sysUser = sysBaseApi.getUserByName(username);
|
LoginUser sysUser = sysBaseApi.getUserByName(username);
|
||||||
if(sysUser!=null) {
|
if(sysUser!=null) {
|
||||||
asyncClearLogoutCache(token, sysUser); // 异步清理
|
asyncClearLogoutCache(token, sysUser); // 异步清理
|
||||||
OAuth2Authorization authorization = authorizationService.findByToken(token, OAuth2TokenType.ACCESS_TOKEN);
|
SecurityUtils.getSubject().logout();
|
||||||
// 清空用户信息
|
return Result.ok("退出登录成功!");
|
||||||
cacheManager.getCache("user_details").evict(authorization.getPrincipalName());
|
|
||||||
// 清空access token
|
|
||||||
authorizationService.remove(authorization);
|
|
||||||
return Result.ok("退出登录成功!");
|
|
||||||
}else {
|
}else {
|
||||||
return Result.error("Token无效!");
|
return Result.error("Token无效!");
|
||||||
}
|
}
|
||||||
@ -230,7 +204,7 @@ public class LoginController {
|
|||||||
*/
|
*/
|
||||||
private void asyncClearLogoutCache(String token, LoginUser sysUser) {
|
private void asyncClearLogoutCache(String token, LoginUser sysUser) {
|
||||||
cachedThreadPool.execute(()->{
|
cachedThreadPool.execute(()->{
|
||||||
//清空用户登录Token缓存
|
//清空用户登录Token缓存
|
||||||
redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + token);
|
redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + token);
|
||||||
//清空用户登录Shiro权限缓存
|
//清空用户登录Shiro权限缓存
|
||||||
redisUtil.del(CommonConstant.PREFIX_USER_SHIRO_CACHE + sysUser.getId());
|
redisUtil.del(CommonConstant.PREFIX_USER_SHIRO_CACHE + sysUser.getId());
|
||||||
@ -306,7 +280,7 @@ public class LoginController {
|
|||||||
Result<JSONObject> result = new Result<JSONObject>();
|
Result<JSONObject> result = new Result<JSONObject>();
|
||||||
String username = user.getUsername();
|
String username = user.getUsername();
|
||||||
if(oConvertUtils.isEmpty(username)) {
|
if(oConvertUtils.isEmpty(username)) {
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
|
||||||
username = sysUser.getUsername();
|
username = sysUser.getUsername();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,7 +318,7 @@ public class LoginController {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//update-begin-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
|
// VUEN-2245【漏洞】发现新漏洞待处理20220906
|
||||||
String redisKey = CommonConstant.PHONE_REDIS_KEY_PRE+mobile;
|
String redisKey = CommonConstant.PHONE_REDIS_KEY_PRE+mobile;
|
||||||
Object object = redisUtil.get(redisKey);
|
Object object = redisUtil.get(redisKey);
|
||||||
|
|
||||||
@ -594,11 +568,6 @@ public class LoginController {
|
|||||||
String oldToken = oldTokenObj.toString();
|
String oldToken = oldTokenObj.toString();
|
||||||
// 清除旧登录token的缓存(设置 1 小时过期时间)
|
// 清除旧登录token的缓存(设置 1 小时过期时间)
|
||||||
redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + oldToken);
|
redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + oldToken);
|
||||||
|
|
||||||
// 清空sas用户信息
|
|
||||||
OAuth2Authorization authorization = authorizationService.findByToken(oldToken, OAuth2TokenType.ACCESS_TOKEN);
|
|
||||||
cacheManager.getCache("user_details").evict(authorization.getPrincipalName());
|
|
||||||
authorizationService.remove(authorization);
|
|
||||||
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN_ERROR_MSG + oldToken, "不允许同一账号多地同时登录,当前登录被踢掉!", 60 * 1 * 60);
|
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN_ERROR_MSG + oldToken, "不允许同一账号多地同时登录,当前登录被踢掉!", 60 * 1 * 60);
|
||||||
log.info("【并发登录限制已开启】用户[{}]在{}端的旧登录已被踢下线!", username, clientType);
|
log.info("【并发登录限制已开启】用户[{}]在{}端的旧登录已被踢下线!", username, clientType);
|
||||||
log.info("【并发登录限制已开启】用户被踢下线,新token: {},旧token:{}", newToken, oldToken);
|
log.info("【并发登录限制已开启】用户被踢下线,新token: {},旧token:{}", newToken, oldToken);
|
||||||
@ -869,7 +838,7 @@ public class LoginController {
|
|||||||
result.setSuccess(false);
|
result.setSuccess(false);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
String username = sysUser.getUsername();
|
String username = sysUser.getUsername();
|
||||||
LambdaQueryWrapper<SysUser> query = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<SysUser> query = new LambdaQueryWrapper<>();
|
||||||
query.eq(SysUser::getUsername, username).eq(SysUser::getPhone, mobile);
|
query.eq(SysUser::getUsername, username).eq(SysUser::getPhone, mobile);
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
package org.jeecg.modules.system.controller;
|
package org.jeecg.modules.system.controller;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.alibaba.fastjson.JSONArray;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
@ -23,7 +21,6 @@ import org.jeecg.common.system.util.JwtUtil;
|
|||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import org.jeecg.common.util.*;
|
import org.jeecg.common.util.*;
|
||||||
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecg.modules.message.enums.RangeDateEnum;
|
import org.jeecg.modules.message.enums.RangeDateEnum;
|
||||||
import org.jeecg.modules.message.websocket.WebSocket;
|
import org.jeecg.modules.message.websocket.WebSocket;
|
||||||
import org.jeecg.modules.system.entity.SysAnnouncement;
|
import org.jeecg.modules.system.entity.SysAnnouncement;
|
||||||
@ -43,7 +40,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
@ -392,7 +388,7 @@ public class SysAnnouncementController {
|
|||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
Result<Map<String,Object>> result = new Result<Map<String,Object>>();
|
Result<Map<String,Object>> result = new Result<Map<String,Object>>();
|
||||||
Map<String,Object> sysMsgMap = new HashMap(5);
|
Map<String,Object> sysMsgMap = new HashMap(5);
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
|
||||||
String userId = sysUser.getId();
|
String userId = sysUser.getId();
|
||||||
|
|
||||||
|
|
||||||
@ -477,7 +473,7 @@ public class SysAnnouncementController {
|
|||||||
//导出文件名称
|
//导出文件名称
|
||||||
mv.addObject(NormalExcelConstants.FILE_NAME, "系统通告列表");
|
mv.addObject(NormalExcelConstants.FILE_NAME, "系统通告列表");
|
||||||
mv.addObject(NormalExcelConstants.CLASS, SysAnnouncement.class);
|
mv.addObject(NormalExcelConstants.CLASS, SysAnnouncement.class);
|
||||||
LoginUser user = SecureUtil.currentUser();
|
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("系统通告列表数据", "导出人:"+user.getRealname(), "导出信息"));
|
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("系统通告列表数据", "导出人:"+user.getRealname(), "导出信息"));
|
||||||
mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
|
mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
|
||||||
return mv;
|
return mv;
|
||||||
@ -654,7 +650,7 @@ public class SysAnnouncementController {
|
|||||||
|
|
||||||
JSONObject obj = new JSONObject();
|
JSONObject obj = new JSONObject();
|
||||||
obj.put(WebsocketConst.MSG_CMD, WebsocketConst.CMD_USER);
|
obj.put(WebsocketConst.MSG_CMD, WebsocketConst.CMD_USER);
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
webSocket.sendMessage(sysUser.getId(), obj.toJSONString());
|
webSocket.sendMessage(sysUser.getId(), obj.toJSONString());
|
||||||
|
|
||||||
// 4、性能统计耗时
|
// 4、性能统计耗时
|
||||||
|
|||||||
@ -3,10 +3,10 @@ package org.jeecg.modules.system.controller;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.constant.DataBaseConstant;
|
import org.jeecg.common.constant.DataBaseConstant;
|
||||||
@ -14,13 +14,11 @@ import org.jeecg.common.constant.WebsocketConst;
|
|||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import org.jeecg.common.util.SqlInjectionUtil;
|
import org.jeecg.common.util.SqlInjectionUtil;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecg.modules.message.websocket.WebSocket;
|
import org.jeecg.modules.message.websocket.WebSocket;
|
||||||
import org.jeecg.modules.system.entity.SysAnnouncementSend;
|
import org.jeecg.modules.system.entity.SysAnnouncementSend;
|
||||||
import org.jeecg.modules.system.model.AnnouncementSendModel;
|
import org.jeecg.modules.system.model.AnnouncementSendModel;
|
||||||
import org.jeecg.modules.system.service.ISysAnnouncementSendService;
|
import org.jeecg.modules.system.service.ISysAnnouncementSendService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -198,7 +196,7 @@ public class SysAnnouncementSendController {
|
|||||||
public Result<SysAnnouncementSend> editById(@RequestBody JSONObject json) {
|
public Result<SysAnnouncementSend> editById(@RequestBody JSONObject json) {
|
||||||
Result<SysAnnouncementSend> result = new Result<SysAnnouncementSend>();
|
Result<SysAnnouncementSend> result = new Result<SysAnnouncementSend>();
|
||||||
String anntId = json.getString("anntId");
|
String anntId = json.getString("anntId");
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
|
||||||
String userId = sysUser.getId();
|
String userId = sysUser.getId();
|
||||||
LambdaUpdateWrapper<SysAnnouncementSend> updateWrapper = new UpdateWrapper().lambda();
|
LambdaUpdateWrapper<SysAnnouncementSend> updateWrapper = new UpdateWrapper().lambda();
|
||||||
updateWrapper.set(SysAnnouncementSend::getReadFlag, CommonConstant.HAS_READ_FLAG);
|
updateWrapper.set(SysAnnouncementSend::getReadFlag, CommonConstant.HAS_READ_FLAG);
|
||||||
@ -222,7 +220,7 @@ public class SysAnnouncementSendController {
|
|||||||
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
|
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
|
||||||
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize) {
|
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize) {
|
||||||
Result<IPage<AnnouncementSendModel>> result = new Result<IPage<AnnouncementSendModel>>();
|
Result<IPage<AnnouncementSendModel>> result = new Result<IPage<AnnouncementSendModel>>();
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
|
||||||
String userId = sysUser.getId();
|
String userId = sysUser.getId();
|
||||||
announcementSendModel.setUserId(userId);
|
announcementSendModel.setUserId(userId);
|
||||||
announcementSendModel.setPageNo((pageNo-1)*pageSize);
|
announcementSendModel.setPageNo((pageNo-1)*pageSize);
|
||||||
@ -248,7 +246,7 @@ public class SysAnnouncementSendController {
|
|||||||
@PutMapping(value = "/readAll")
|
@PutMapping(value = "/readAll")
|
||||||
public Result<SysAnnouncementSend> readAll() {
|
public Result<SysAnnouncementSend> readAll() {
|
||||||
Result<SysAnnouncementSend> result = new Result<SysAnnouncementSend>();
|
Result<SysAnnouncementSend> result = new Result<SysAnnouncementSend>();
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
|
||||||
String userId = sysUser.getId();
|
String userId = sysUser.getId();
|
||||||
LambdaUpdateWrapper<SysAnnouncementSend> updateWrapper = new UpdateWrapper().lambda();
|
LambdaUpdateWrapper<SysAnnouncementSend> updateWrapper = new UpdateWrapper().lambda();
|
||||||
updateWrapper.set(SysAnnouncementSend::getReadFlag, CommonConstant.HAS_READ_FLAG);
|
updateWrapper.set(SysAnnouncementSend::getReadFlag, CommonConstant.HAS_READ_FLAG);
|
||||||
@ -292,7 +290,7 @@ public class SysAnnouncementSendController {
|
|||||||
//刷新未读数量
|
//刷新未读数量
|
||||||
JSONObject obj = new JSONObject();
|
JSONObject obj = new JSONObject();
|
||||||
obj.put(WebsocketConst.MSG_CMD, WebsocketConst.CMD_USER);
|
obj.put(WebsocketConst.MSG_CMD, WebsocketConst.CMD_USER);
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
webSocket.sendMessage(sysUser.getId(), obj.toJSONString());
|
webSocket.sendMessage(sysUser.getId(), obj.toJSONString());
|
||||||
|
|
||||||
return Result.ok();
|
return Result.ok();
|
||||||
|
|||||||
@ -3,13 +3,12 @@ package org.jeecg.modules.system.controller;
|
|||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.util.RedisUtil;
|
import org.jeecg.common.util.RedisUtil;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.modules.jmreport.common.annotation.RequiresRoles;
|
|
||||||
import org.jeecg.modules.system.entity.SysAppVersion;
|
import org.jeecg.modules.system.entity.SysAppVersion;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,7 +57,7 @@ public class SysAppVersionController{
|
|||||||
* @param sysAppVersion
|
* @param sysAppVersion
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresRoles('admin')")
|
@RequiresRoles({"admin"})
|
||||||
@Operation(summary="app系统配置-保存")
|
@Operation(summary="app系统配置-保存")
|
||||||
@PostMapping(value = "/saveVersion")
|
@PostMapping(value = "/saveVersion")
|
||||||
public Result<?> saveVersion(@RequestBody SysAppVersion sysAppVersion) {
|
public Result<?> saveVersion(@RequestBody SysAppVersion sysAppVersion) {
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
|||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.config.TenantContext;
|
import org.jeecg.common.config.TenantContext;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
@ -17,7 +18,6 @@ import org.jeecg.common.util.ImportExcelUtil;
|
|||||||
import org.jeecg.common.util.ReflectHelper;
|
import org.jeecg.common.util.ReflectHelper;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecg.modules.system.entity.SysCategory;
|
import org.jeecg.modules.system.entity.SysCategory;
|
||||||
import org.jeecg.modules.system.model.TreeSelectModel;
|
import org.jeecg.modules.system.model.TreeSelectModel;
|
||||||
import org.jeecg.modules.system.service.ISysCategoryService;
|
import org.jeecg.modules.system.service.ISysCategoryService;
|
||||||
@ -28,7 +28,6 @@ import org.jeecgframework.poi.excel.entity.ImportParams;
|
|||||||
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
|
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
|
||||||
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
|
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||||
@ -239,7 +238,7 @@ public class SysCategoryController {
|
|||||||
//导出文件名称
|
//导出文件名称
|
||||||
mv.addObject(NormalExcelConstants.FILE_NAME, "分类字典列表");
|
mv.addObject(NormalExcelConstants.FILE_NAME, "分类字典列表");
|
||||||
mv.addObject(NormalExcelConstants.CLASS, SysCategory.class);
|
mv.addObject(NormalExcelConstants.CLASS, SysCategory.class);
|
||||||
LoginUser user = SecureUtil.currentUser();
|
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
//导出支持xlsx
|
//导出支持xlsx
|
||||||
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("分类字典列表数据", "导出人:"+user.getRealname(), "导出信息", ExcelType.XSSF));
|
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("分类字典列表数据", "导出人:"+user.getRealname(), "导出信息", ExcelType.XSSF));
|
||||||
//分类字典导出支持导出字段
|
//分类字典导出支持导出字段
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
package org.jeecg.modules.system.controller;
|
package org.jeecg.modules.system.controller;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
import org.jeecg.common.api.dto.DataLogDTO;
|
import org.jeecg.common.api.dto.DataLogDTO;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
@ -14,14 +14,12 @@ import org.jeecg.common.system.api.ISysBaseAPI;
|
|||||||
import org.jeecg.common.system.base.controller.JeecgController;
|
import org.jeecg.common.system.base.controller.JeecgController;
|
||||||
import org.jeecg.common.system.query.QueryGenerator;
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecg.modules.system.entity.SysComment;
|
import org.jeecg.modules.system.entity.SysComment;
|
||||||
import org.jeecg.modules.system.service.ISysCommentService;
|
import org.jeecg.modules.system.service.ISysCommentService;
|
||||||
import org.jeecg.modules.system.vo.SysCommentFileVo;
|
import org.jeecg.modules.system.vo.SysCommentFileVo;
|
||||||
import org.jeecg.modules.system.vo.SysCommentVO;
|
import org.jeecg.modules.system.vo.SysCommentVO;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
@ -128,7 +126,7 @@ public class SysCommentController extends JeecgController<SysComment, ISysCommen
|
|||||||
if(comment==null){
|
if(comment==null){
|
||||||
return Result.error("该评论已被删除!");
|
return Result.error("该评论已被删除!");
|
||||||
}
|
}
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
String username = sysUser.getUsername();
|
String username = sysUser.getUsername();
|
||||||
String admin = "admin";
|
String admin = "admin";
|
||||||
//除了admin外 其他人只能删除自己的评论
|
//除了admin外 其他人只能删除自己的评论
|
||||||
|
|||||||
@ -7,12 +7,12 @@ import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
|
|||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.aspect.annotation.AutoLog;
|
import org.jeecg.common.aspect.annotation.AutoLog;
|
||||||
import org.jeecg.common.config.TenantContext;
|
import org.jeecg.common.config.TenantContext;
|
||||||
@ -27,7 +27,6 @@ import org.jeecg.modules.system.entity.SysDataSource;
|
|||||||
import org.jeecg.modules.system.service.ISysDataSourceService;
|
import org.jeecg.modules.system.service.ISysDataSourceService;
|
||||||
import org.jeecg.modules.system.util.SecurityUtil;
|
import org.jeecg.modules.system.util.SecurityUtil;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
@ -64,7 +63,7 @@ public class SysDataSourceController extends JeecgController<SysDataSource, ISys
|
|||||||
*/
|
*/
|
||||||
@AutoLog(value = "多数据源管理-分页列表查询")
|
@AutoLog(value = "多数据源管理-分页列表查询")
|
||||||
@Operation(summary = "多数据源管理-分页列表查询")
|
@Operation(summary = "多数据源管理-分页列表查询")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:datasource:list')")
|
@RequiresPermissions("system:datasource:list")
|
||||||
@GetMapping(value = "/list")
|
@GetMapping(value = "/list")
|
||||||
public Result<?> queryPageList(
|
public Result<?> queryPageList(
|
||||||
SysDataSource sysDataSource,
|
SysDataSource sysDataSource,
|
||||||
@ -132,7 +131,7 @@ public class SysDataSourceController extends JeecgController<SysDataSource, ISys
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@AutoLog(value = "多数据源管理-编辑")
|
@AutoLog(value = "多数据源管理-编辑")
|
||||||
@Operation(summary = "多数据源管理-编辑")
|
@Operation(summary = "多数据源管理-编辑")
|
||||||
@RequestMapping(value = "/edit", method ={RequestMethod.PUT, RequestMethod.POST})
|
@RequestMapping(value = "/edit", method ={RequestMethod.PUT, RequestMethod.POST})
|
||||||
public Result<?> edit(@RequestBody SysDataSource sysDataSource) {
|
public Result<?> edit(@RequestBody SysDataSource sysDataSource) {
|
||||||
// 代码逻辑说明: jdbc连接地址漏洞问题
|
// 代码逻辑说明: jdbc连接地址漏洞问题
|
||||||
@ -165,7 +164,7 @@ public class SysDataSourceController extends JeecgController<SysDataSource, ISys
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@AutoLog(value = "多数据源管理-批量删除")
|
@AutoLog(value = "多数据源管理-批量删除")
|
||||||
@Operation(summary = "多数据源管理-批量删除")
|
@Operation(summary = "多数据源管理-批量删除")
|
||||||
@DeleteMapping(value = "/deleteBatch")
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
public Result<?> deleteBatch(@RequestParam(name = "ids") String ids) {
|
public Result<?> deleteBatch(@RequestParam(name = "ids") String ids) {
|
||||||
List<String> idList = Arrays.asList(ids.split(","));
|
List<String> idList = Arrays.asList(ids.split(","));
|
||||||
|
|||||||
@ -1,27 +1,24 @@
|
|||||||
package org.jeecg.modules.system.controller;
|
package org.jeecg.modules.system.controller;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.config.TenantContext;
|
import org.jeecg.common.config.TenantContext;
|
||||||
import org.jeecg.common.constant.CacheConstant;
|
import org.jeecg.common.constant.CacheConstant;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.system.query.QueryGenerator;
|
|
||||||
import org.jeecg.common.system.util.JwtUtil;
|
import org.jeecg.common.system.util.JwtUtil;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import org.jeecg.common.util.ImportExcelUtil;
|
import org.jeecg.common.util.ImportExcelUtil;
|
||||||
import org.jeecg.common.util.RedisUtil;
|
import org.jeecg.common.util.RedisUtil;
|
||||||
import org.jeecg.common.util.YouBianCodeUtil;
|
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecg.modules.jmreport.common.annotation.RequiresRoles;
|
|
||||||
import org.jeecg.modules.system.entity.SysDepart;
|
import org.jeecg.modules.system.entity.SysDepart;
|
||||||
import org.jeecg.modules.system.entity.SysUser;
|
import org.jeecg.modules.system.entity.SysUser;
|
||||||
import org.jeecg.modules.system.excelstyle.ExcelExportSysUserStyle;
|
import org.jeecg.modules.system.excelstyle.ExcelExportSysUserStyle;
|
||||||
@ -43,8 +40,6 @@ import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.cache.annotation.CacheEvict;
|
import org.springframework.cache.annotation.CacheEvict;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||||
@ -85,7 +80,7 @@ public class SysDepartController {
|
|||||||
@RequestMapping(value = "/queryMyDeptTreeList", method = RequestMethod.GET)
|
@RequestMapping(value = "/queryMyDeptTreeList", method = RequestMethod.GET)
|
||||||
public Result<List<SysDepartTreeModel>> queryMyDeptTreeList() {
|
public Result<List<SysDepartTreeModel>> queryMyDeptTreeList() {
|
||||||
Result<List<SysDepartTreeModel>> result = new Result<>();
|
Result<List<SysDepartTreeModel>> result = new Result<>();
|
||||||
LoginUser user = SecureUtil.currentUser();
|
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
try {
|
try {
|
||||||
if(oConvertUtils.isNotEmpty(user.getUserIdentity()) && user.getUserIdentity().equals( CommonConstant.USER_IDENTITY_2 )){
|
if(oConvertUtils.isNotEmpty(user.getUserIdentity()) && user.getUserIdentity().equals( CommonConstant.USER_IDENTITY_2 )){
|
||||||
// 代码逻辑说明: 部门查询ids为空后的前端显示问题 issues/I3UD06
|
// 代码逻辑说明: 部门查询ids为空后的前端显示问题 issues/I3UD06
|
||||||
@ -214,7 +209,7 @@ public class SysDepartController {
|
|||||||
* @param sysDepart
|
* @param sysDepart
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:depart:add')")
|
@RequiresPermissions("system:depart:add")
|
||||||
@RequestMapping(value = "/add", method = RequestMethod.POST)
|
@RequestMapping(value = "/add", method = RequestMethod.POST)
|
||||||
@CacheEvict(value= {CacheConstant.SYS_DEPARTS_CACHE,CacheConstant.SYS_DEPART_IDS_CACHE}, allEntries=true)
|
@CacheEvict(value= {CacheConstant.SYS_DEPARTS_CACHE,CacheConstant.SYS_DEPART_IDS_CACHE}, allEntries=true)
|
||||||
public Result<SysDepart> add(@RequestBody SysDepart sysDepart, HttpServletRequest request) {
|
public Result<SysDepart> add(@RequestBody SysDepart sysDepart, HttpServletRequest request) {
|
||||||
@ -240,7 +235,7 @@ public class SysDepartController {
|
|||||||
* @param sysDepart
|
* @param sysDepart
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:depart:edit')")
|
@RequiresPermissions("system:depart:edit")
|
||||||
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
|
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
|
||||||
@CacheEvict(value= {CacheConstant.SYS_DEPARTS_CACHE,CacheConstant.SYS_DEPART_IDS_CACHE}, allEntries=true)
|
@CacheEvict(value= {CacheConstant.SYS_DEPARTS_CACHE,CacheConstant.SYS_DEPART_IDS_CACHE}, allEntries=true)
|
||||||
public Result<SysDepart> edit(@RequestBody SysDepart sysDepart, HttpServletRequest request) {
|
public Result<SysDepart> edit(@RequestBody SysDepart sysDepart, HttpServletRequest request) {
|
||||||
@ -268,7 +263,7 @@ public class SysDepartController {
|
|||||||
* @param id
|
* @param id
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:depart:delete')")
|
@RequiresPermissions("system:depart:delete")
|
||||||
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
|
||||||
@CacheEvict(value= {CacheConstant.SYS_DEPARTS_CACHE,CacheConstant.SYS_DEPART_IDS_CACHE}, allEntries=true)
|
@CacheEvict(value= {CacheConstant.SYS_DEPARTS_CACHE,CacheConstant.SYS_DEPART_IDS_CACHE}, allEntries=true)
|
||||||
public Result<SysDepart> delete(@RequestParam(name="id",required=true) String id) {
|
public Result<SysDepart> delete(@RequestParam(name="id",required=true) String id) {
|
||||||
@ -294,7 +289,7 @@ public class SysDepartController {
|
|||||||
* @param ids
|
* @param ids
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:depart:deleteBatch')")
|
@RequiresPermissions("system:depart:deleteBatch")
|
||||||
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
|
||||||
@CacheEvict(value= {CacheConstant.SYS_DEPARTS_CACHE,CacheConstant.SYS_DEPART_IDS_CACHE}, allEntries=true)
|
@CacheEvict(value= {CacheConstant.SYS_DEPARTS_CACHE,CacheConstant.SYS_DEPART_IDS_CACHE}, allEntries=true)
|
||||||
public Result<SysDepart> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
public Result<SysDepart> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
||||||
@ -361,7 +356,7 @@ public class SysDepartController {
|
|||||||
@RequestParam(name = "departIds", required = false) String depIds) {
|
@RequestParam(name = "departIds", required = false) String depIds) {
|
||||||
Result<List<SysDepartTreeModel>> result = new Result<List<SysDepartTreeModel>>();
|
Result<List<SysDepartTreeModel>> result = new Result<List<SysDepartTreeModel>>();
|
||||||
//部门查询,myDeptSearch为1时为我的部门查询,登录用户为上级时查只查负责部门下数据
|
//部门查询,myDeptSearch为1时为我的部门查询,登录用户为上级时查只查负责部门下数据
|
||||||
LoginUser user = SecureUtil.currentUser();
|
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
String departIds = null;
|
String departIds = null;
|
||||||
if(oConvertUtils.isNotEmpty(user.getUserIdentity()) && user.getUserIdentity().equals( CommonConstant.USER_IDENTITY_2 )){
|
if(oConvertUtils.isNotEmpty(user.getUserIdentity()) && user.getUserIdentity().equals( CommonConstant.USER_IDENTITY_2 )){
|
||||||
departIds = user.getDepartIds();
|
departIds = user.getDepartIds();
|
||||||
@ -416,7 +411,7 @@ public class SysDepartController {
|
|||||||
//导出文件名称
|
//导出文件名称
|
||||||
mv.addObject(NormalExcelConstants.FILE_NAME, "部门列表");
|
mv.addObject(NormalExcelConstants.FILE_NAME, "部门列表");
|
||||||
mv.addObject(NormalExcelConstants.CLASS, SysDepartExportVo.class);
|
mv.addObject(NormalExcelConstants.CLASS, SysDepartExportVo.class);
|
||||||
LoginUser user = SecureUtil.currentUser();
|
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
ExportParams exportParams = new ExportParams("导入规则:\n" +
|
ExportParams exportParams = new ExportParams("导入规则:\n" +
|
||||||
"1、标题为第三行,部门路径和部门名称的标题不允许修改,否则会匹配失败;第四行为数据填写范围;\n" +
|
"1、标题为第三行,部门路径和部门名称的标题不允许修改,否则会匹配失败;第四行为数据填写范围;\n" +
|
||||||
"2、部门路径用英文字符/分割,部门名称为部门路径的最后一位;\n" +
|
"2、部门路径用英文字符/分割,部门名称为部门路径的最后一位;\n" +
|
||||||
@ -439,7 +434,7 @@ public class SysDepartController {
|
|||||||
* @param response
|
* @param response
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:depart:importExcel')")
|
@RequiresPermissions("system:depart:importExcel")
|
||||||
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
|
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
|
||||||
@CacheEvict(value= {CacheConstant.SYS_DEPARTS_CACHE,CacheConstant.SYS_DEPART_IDS_CACHE}, allEntries=true)
|
@CacheEvict(value= {CacheConstant.SYS_DEPARTS_CACHE,CacheConstant.SYS_DEPART_IDS_CACHE}, allEntries=true)
|
||||||
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
|
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
|
||||||
@ -673,7 +668,7 @@ public class SysDepartController {
|
|||||||
//导出文件名称
|
//导出文件名称
|
||||||
mv.addObject(NormalExcelConstants.FILE_NAME, "部门列表");
|
mv.addObject(NormalExcelConstants.FILE_NAME, "部门列表");
|
||||||
mv.addObject(NormalExcelConstants.CLASS, ExportDepartVo.class);
|
mv.addObject(NormalExcelConstants.CLASS, ExportDepartVo.class);
|
||||||
LoginUser user = SecureUtil.currentUser();
|
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("部门列表数据", "导出人:"+user.getRealname(), "导出信息"));
|
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("部门列表数据", "导出人:"+user.getRealname(), "导出信息"));
|
||||||
mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
|
mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
|
||||||
return mv;
|
return mv;
|
||||||
@ -776,7 +771,7 @@ public class SysDepartController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PutMapping("/updateChangeDepart")
|
@PutMapping("/updateChangeDepart")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:depart:updateChange')")
|
@RequiresPermissions("system:depart:updateChange")
|
||||||
@RequiresRoles({"admin"})
|
@RequiresRoles({"admin"})
|
||||||
public Result<String> updateChangeDepart(@RequestBody SysChangeDepartVo changeDepartVo) {
|
public Result<String> updateChangeDepart(@RequestBody SysChangeDepartVo changeDepartVo) {
|
||||||
sysDepartService.updateChangeDepart(changeDepartVo);
|
sysDepartService.updateChangeDepart(changeDepartVo);
|
||||||
|
|||||||
@ -1,23 +1,19 @@
|
|||||||
package org.jeecg.modules.system.controller;
|
package org.jeecg.modules.system.controller;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import org.apache.shiro.SecurityUtils;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.system.base.controller.JeecgController;
|
|
||||||
import org.jeecg.common.system.query.QueryGenerator;
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
import org.jeecg.common.aspect.annotation.AutoLog;
|
import org.jeecg.common.aspect.annotation.AutoLog;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecg.modules.base.service.BaseCommonService;
|
import org.jeecg.modules.base.service.BaseCommonService;
|
||||||
import org.jeecg.modules.system.entity.SysDepartPermission;
|
import org.jeecg.modules.system.entity.SysDepartPermission;
|
||||||
import org.jeecg.modules.system.entity.SysDepartRolePermission;
|
import org.jeecg.modules.system.entity.SysDepartRolePermission;
|
||||||
@ -35,12 +31,10 @@ import org.jeecg.modules.system.service.ISysPermissionDataRuleService;
|
|||||||
import org.jeecg.modules.system.service.ISysPermissionService;
|
import org.jeecg.modules.system.service.ISysPermissionService;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import java.util.*;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Description: 部门权限表
|
* @Description: 部门权限表
|
||||||
@ -266,7 +260,7 @@ public class SysDepartPermissionController extends JeecgController<SysDepartPerm
|
|||||||
this.sysDepartRolePermissionService.saveDeptRolePermission(roleId, permissionIds, lastPermissionIds);
|
this.sysDepartRolePermissionService.saveDeptRolePermission(roleId, permissionIds, lastPermissionIds);
|
||||||
result.success("保存成功!");
|
result.success("保存成功!");
|
||||||
// 代码逻辑说明: [VUEN-234]部门角色授权添加敏感日志------------
|
// 代码逻辑说明: [VUEN-234]部门角色授权添加敏感日志------------
|
||||||
LoginUser loginUser = SecureUtil.currentUser();
|
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
baseCommonService.addLog("修改部门角色ID:"+roleId+"的权限配置,操作人: " +loginUser.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
|
baseCommonService.addLog("修改部门角色ID:"+roleId+"的权限配置,操作人: " +loginUser.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
|
||||||
log.info("======部门角色授权成功=====耗时:" + (System.currentTimeMillis() - start) + "毫秒");
|
log.info("======部门角色授权成功=====耗时:" + (System.currentTimeMillis() - start) + "毫秒");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|||||||
@ -1,39 +1,35 @@
|
|||||||
package org.jeecg.modules.system.controller;
|
package org.jeecg.modules.system.controller;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||||
|
import org.jeecg.common.api.vo.Result;
|
||||||
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
|
import org.jeecg.common.aspect.annotation.AutoLog;
|
||||||
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
|
import org.jeecg.modules.base.service.BaseCommonService;
|
||||||
|
import org.jeecg.modules.system.entity.*;
|
||||||
|
import org.jeecg.modules.system.service.*;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jeecg.common.api.vo.Result;
|
|
||||||
import org.jeecg.common.aspect.annotation.AutoLog;
|
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
|
||||||
import org.jeecg.common.system.base.controller.JeecgController;
|
import org.jeecg.common.system.base.controller.JeecgController;
|
||||||
import org.jeecg.common.system.query.QueryGenerator;
|
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecg.modules.base.service.BaseCommonService;
|
|
||||||
import org.jeecg.modules.system.entity.SysDepartRole;
|
|
||||||
import org.jeecg.modules.system.entity.SysDepartRolePermission;
|
|
||||||
import org.jeecg.modules.system.entity.SysDepartRoleUser;
|
|
||||||
import org.jeecg.modules.system.entity.SysPermissionDataRule;
|
|
||||||
import org.jeecg.modules.system.service.*;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import java.util.Arrays;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Description: 部门角色
|
* @Description: 部门角色
|
||||||
@ -112,7 +108,7 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
|
|||||||
* @param sysDepartRole
|
* @param sysDepartRole
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:depart:role:add')")
|
@RequiresPermissions("system:depart:role:add")
|
||||||
@Operation(summary="部门角色-添加")
|
@Operation(summary="部门角色-添加")
|
||||||
@PostMapping(value = "/add")
|
@PostMapping(value = "/add")
|
||||||
public Result<?> add(@RequestBody SysDepartRole sysDepartRole) {
|
public Result<?> add(@RequestBody SysDepartRole sysDepartRole) {
|
||||||
@ -127,7 +123,7 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Operation(summary="部门角色-编辑")
|
@Operation(summary="部门角色-编辑")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:depart:role:edit')")
|
@RequiresPermissions("system:depart:role:edit")
|
||||||
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
|
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
|
||||||
public Result<?> edit(@RequestBody SysDepartRole sysDepartRole) {
|
public Result<?> edit(@RequestBody SysDepartRole sysDepartRole) {
|
||||||
sysDepartRoleService.updateById(sysDepartRole);
|
sysDepartRoleService.updateById(sysDepartRole);
|
||||||
@ -142,7 +138,7 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
|
|||||||
*/
|
*/
|
||||||
@AutoLog(value = "部门角色-通过id删除")
|
@AutoLog(value = "部门角色-通过id删除")
|
||||||
@Operation(summary="部门角色-通过id删除")
|
@Operation(summary="部门角色-通过id删除")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:depart:role:delete')")
|
@RequiresPermissions("system:depart:role:delete")
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
public Result<?> delete(@RequestParam(name="id",required=true) String id) {
|
public Result<?> delete(@RequestParam(name="id",required=true) String id) {
|
||||||
sysDepartRoleService.removeById(id);
|
sysDepartRoleService.removeById(id);
|
||||||
@ -157,7 +153,7 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
|
|||||||
*/
|
*/
|
||||||
@AutoLog(value = "部门角色-批量删除")
|
@AutoLog(value = "部门角色-批量删除")
|
||||||
@Operation(summary="部门角色-批量删除")
|
@Operation(summary="部门角色-批量删除")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:depart:role:deleteBatch')")
|
@RequiresPermissions("system:depart:role:deleteBatch")
|
||||||
@DeleteMapping(value = "/deleteBatch")
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
public Result<?> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
|
public Result<?> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
|
||||||
this.sysDepartRoleService.deleteDepartRole(Arrays.asList(ids.split(",")));
|
this.sysDepartRoleService.deleteDepartRole(Arrays.asList(ids.split(",")));
|
||||||
@ -198,7 +194,7 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
|
|||||||
* @param json
|
* @param json
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:depart:role:userAdd')")
|
@RequiresPermissions("system:depart:role:userAdd")
|
||||||
@RequestMapping(value = "/deptRoleUserAdd", method = RequestMethod.POST)
|
@RequestMapping(value = "/deptRoleUserAdd", method = RequestMethod.POST)
|
||||||
public Result<?> deptRoleAdd(@RequestBody JSONObject json) {
|
public Result<?> deptRoleAdd(@RequestBody JSONObject json) {
|
||||||
String newRoleId = json.getString("newRoleId");
|
String newRoleId = json.getString("newRoleId");
|
||||||
@ -206,7 +202,7 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
|
|||||||
String userId = json.getString("userId");
|
String userId = json.getString("userId");
|
||||||
departRoleUserService.deptRoleUserAdd(userId,newRoleId,oldRoleId);
|
departRoleUserService.deptRoleUserAdd(userId,newRoleId,oldRoleId);
|
||||||
// 代码逻辑说明: [VUEN-234]部门角色分配添加敏感日志------------
|
// 代码逻辑说明: [VUEN-234]部门角色分配添加敏感日志------------
|
||||||
LoginUser loginUser = SecureUtil.currentUser();
|
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
baseCommonService.addLog("给部门用户ID:"+userId+"分配角色,操作人: " +loginUser.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
|
baseCommonService.addLog("给部门用户ID:"+userId+"分配角色,操作人: " +loginUser.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
|
||||||
return Result.ok("添加成功!");
|
return Result.ok("添加成功!");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,9 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
|||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
|
import org.apache.shiro.subject.Subject;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.config.TenantContext;
|
import org.jeecg.common.config.TenantContext;
|
||||||
import org.jeecg.common.constant.CacheConstant;
|
import org.jeecg.common.constant.CacheConstant;
|
||||||
@ -20,8 +23,7 @@ import org.jeecg.common.system.vo.DictQuery;
|
|||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import org.jeecg.common.util.*;
|
import org.jeecg.common.util.*;
|
||||||
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
||||||
import org.jeecg.config.security.JeecgPermissionService;
|
import org.jeecg.config.shiro.ShiroRealm;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecg.modules.system.constant.DefIndexConst;
|
import org.jeecg.modules.system.constant.DefIndexConst;
|
||||||
import org.jeecg.modules.system.entity.SysDict;
|
import org.jeecg.modules.system.entity.SysDict;
|
||||||
import org.jeecg.modules.system.entity.SysDictItem;
|
import org.jeecg.modules.system.entity.SysDictItem;
|
||||||
@ -42,8 +44,6 @@ import org.springframework.beans.BeanUtils;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.cache.annotation.CacheEvict;
|
import org.springframework.cache.annotation.CacheEvict;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||||
@ -76,8 +76,8 @@ public class SysDictController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private RedisUtil redisUtil;
|
private RedisUtil redisUtil;
|
||||||
@Autowired
|
@Autowired
|
||||||
private JeecgPermissionService jeecgPermissionService;
|
private ShiroRealm shiroRealm;
|
||||||
|
|
||||||
@RequestMapping(value = "/list", method = RequestMethod.GET)
|
@RequestMapping(value = "/list", method = RequestMethod.GET)
|
||||||
public Result<IPage<SysDict>> queryPageList(
|
public Result<IPage<SysDict>> queryPageList(
|
||||||
SysDict sysDict,
|
SysDict sysDict,
|
||||||
@ -390,7 +390,7 @@ public class SysDictController {
|
|||||||
* @param sysDict
|
* @param sysDict
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:dict:add')")
|
@RequiresPermissions("system:dict:add")
|
||||||
@RequestMapping(value = "/add", method = RequestMethod.POST)
|
@RequestMapping(value = "/add", method = RequestMethod.POST)
|
||||||
public Result<SysDict> add(@RequestBody SysDict sysDict) {
|
public Result<SysDict> add(@RequestBody SysDict sysDict) {
|
||||||
Result<SysDict> result = new Result<SysDict>();
|
Result<SysDict> result = new Result<SysDict>();
|
||||||
@ -411,7 +411,7 @@ public class SysDictController {
|
|||||||
* @param sysDict
|
* @param sysDict
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:dict:edit')")
|
@RequiresPermissions("system:dict:edit")
|
||||||
@RequestMapping(value = "/edit", method = { RequestMethod.PUT,RequestMethod.POST })
|
@RequestMapping(value = "/edit", method = { RequestMethod.PUT,RequestMethod.POST })
|
||||||
public Result<SysDict> edit(@RequestBody SysDict sysDict) {
|
public Result<SysDict> edit(@RequestBody SysDict sysDict) {
|
||||||
Result<SysDict> result = new Result<SysDict>();
|
Result<SysDict> result = new Result<SysDict>();
|
||||||
@ -433,7 +433,7 @@ public class SysDictController {
|
|||||||
* @param id
|
* @param id
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:dict:delete')")
|
@RequiresPermissions("system:dict:delete")
|
||||||
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
|
||||||
@CacheEvict(value={CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true)
|
@CacheEvict(value={CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true)
|
||||||
public Result<SysDict> delete(@RequestParam(name="id",required=true) String id) {
|
public Result<SysDict> delete(@RequestParam(name="id",required=true) String id) {
|
||||||
@ -452,7 +452,7 @@ public class SysDictController {
|
|||||||
* @param ids
|
* @param ids
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:dict:deleteBatch')")
|
@RequiresPermissions("system:dict:deleteBatch")
|
||||||
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
|
||||||
@CacheEvict(value= {CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true)
|
@CacheEvict(value= {CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true)
|
||||||
public Result<SysDict> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
|
public Result<SysDict> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
|
||||||
@ -501,12 +501,14 @@ public class SysDictController {
|
|||||||
redisUtil.removeAll("jmreport:cache:dict");
|
redisUtil.removeAll("jmreport:cache:dict");
|
||||||
redisUtil.removeAll("jmreport:cache:dictTable");
|
redisUtil.removeAll("jmreport:cache:dictTable");
|
||||||
|
|
||||||
//update-begin---author:scott ---date:2024-06-18 for:【TV360X-1320】分配权限必须退出重新登录才生效,造成很多用户困扰---
|
// 清除当前用户的授权缓存信息
|
||||||
// 清除权限缓存
|
Subject currentUser = SecurityUtils.getSubject();
|
||||||
jeecgPermissionService.clearCache();
|
if (currentUser.isAuthenticated()) {
|
||||||
// 清空默认首页缓存(开源版和商业版会串)
|
shiroRealm.clearCache(currentUser.getPrincipals());
|
||||||
redisUtil.del(DefIndexConst.CACHE_KEY + "::" + DefIndexConst.DEF_INDEX_ALL);
|
}
|
||||||
//update-end---author:scott ---date::2024-06-18 for:【TV360X-1320】分配权限必须退出重新登录才生效,造成很多用户困扰---
|
|
||||||
|
// 清空默认首页缓存(开源版和商业版会串)
|
||||||
|
redisUtil.del(DefIndexConst.CACHE_KEY + "::" + DefIndexConst.DEF_INDEX_ALL);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,7 +551,7 @@ public class SysDictController {
|
|||||||
// 注解对象Class
|
// 注解对象Class
|
||||||
mv.addObject(NormalExcelConstants.CLASS, SysDictPage.class);
|
mv.addObject(NormalExcelConstants.CLASS, SysDictPage.class);
|
||||||
// 自定义表格参数
|
// 自定义表格参数
|
||||||
LoginUser user = SecureUtil.currentUser();
|
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("数据字典列表", "导出人:"+user.getRealname(), "数据字典", ExcelType.XSSF));
|
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("数据字典列表", "导出人:"+user.getRealname(), "数据字典", ExcelType.XSSF));
|
||||||
// 导出数据列表
|
// 导出数据列表
|
||||||
mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
|
mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
|
||||||
@ -563,7 +565,7 @@ public class SysDictController {
|
|||||||
* @param
|
* @param
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:dict:importExcel')")
|
@RequiresPermissions("system:dict:importExcel")
|
||||||
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
|
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
|
||||||
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
|
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
|
||||||
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
|
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
|
||||||
@ -700,7 +702,7 @@ public class SysDictController {
|
|||||||
* @param ids 被删除的字典ID,多个id用半角逗号分割
|
* @param ids 被删除的字典ID,多个id用半角逗号分割
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:dict:deleteRecycleBin')")
|
@RequiresPermissions("system:dict:deleteRecycleBin")
|
||||||
@RequestMapping(value = "/deleteRecycleBin", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/deleteRecycleBin", method = RequestMethod.DELETE)
|
||||||
public Result deleteRecycleBin(@RequestParam("ids") String ids) {
|
public Result deleteRecycleBin(@RequestParam("ids") String ids) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -10,6 +10,8 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.constant.CacheConstant;
|
import org.jeecg.common.constant.CacheConstant;
|
||||||
import org.jeecg.common.system.query.QueryGenerator;
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
@ -18,7 +20,6 @@ import org.jeecg.modules.system.entity.SysDictItem;
|
|||||||
import org.jeecg.modules.system.service.ISysDictItemService;
|
import org.jeecg.modules.system.service.ISysDictItemService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.cache.annotation.CacheEvict;
|
import org.springframework.cache.annotation.CacheEvict;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
@ -73,7 +74,7 @@ public class SysDictItemController {
|
|||||||
* @功能:新增
|
* @功能:新增
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:dict:item:add')")
|
@RequiresPermissions("system:dict:item:add")
|
||||||
@RequestMapping(value = "/add", method = RequestMethod.POST)
|
@RequestMapping(value = "/add", method = RequestMethod.POST)
|
||||||
@CacheEvict(value= {CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true)
|
@CacheEvict(value= {CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true)
|
||||||
public Result<SysDictItem> add(@RequestBody SysDictItem sysDictItem) {
|
public Result<SysDictItem> add(@RequestBody SysDictItem sysDictItem) {
|
||||||
@ -94,7 +95,7 @@ public class SysDictItemController {
|
|||||||
* @param sysDictItem
|
* @param sysDictItem
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:dict:item:edit')")
|
@RequiresPermissions("system:dict:item:edit")
|
||||||
@RequestMapping(value = "/edit", method = { RequestMethod.PUT,RequestMethod.POST })
|
@RequestMapping(value = "/edit", method = { RequestMethod.PUT,RequestMethod.POST })
|
||||||
@CacheEvict(value={CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true)
|
@CacheEvict(value={CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true)
|
||||||
public Result<SysDictItem> edit(@RequestBody SysDictItem sysDictItem) {
|
public Result<SysDictItem> edit(@RequestBody SysDictItem sysDictItem) {
|
||||||
@ -118,7 +119,7 @@ public class SysDictItemController {
|
|||||||
* @param id
|
* @param id
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:dict:item:delete')")
|
@RequiresPermissions("system:dict:item:delete")
|
||||||
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
|
||||||
@CacheEvict(value={CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true)
|
@CacheEvict(value={CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true)
|
||||||
public Result<SysDictItem> delete(@RequestParam(name="id",required=true) String id) {
|
public Result<SysDictItem> delete(@RequestParam(name="id",required=true) String id) {
|
||||||
@ -140,7 +141,7 @@ public class SysDictItemController {
|
|||||||
* @param ids
|
* @param ids
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:dict:item:deleteBatch')")
|
@RequiresPermissions("system:dict:item:deleteBatch")
|
||||||
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
|
||||||
@CacheEvict(value={CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true)
|
@CacheEvict(value={CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true)
|
||||||
public Result<SysDictItem> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
|
public Result<SysDictItem> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
|
||||||
|
|||||||
@ -6,13 +6,13 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.system.base.controller.JeecgController;
|
import org.jeecg.common.system.base.controller.JeecgController;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.modules.system.entity.SysGatewayRoute;
|
import org.jeecg.modules.system.entity.SysGatewayRoute;
|
||||||
import org.jeecg.modules.system.service.ISysGatewayRouteService;
|
import org.jeecg.modules.system.service.ISysGatewayRouteService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
@ -70,7 +70,7 @@ public class SysGatewayRouteController extends JeecgController<SysGatewayRoute,
|
|||||||
* @param id
|
* @param id
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:getway:delete')")
|
@RequiresPermissions("system:getway:delete")
|
||||||
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
|
||||||
public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
|
public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
|
||||||
sysGatewayRouteService.deleteById(id);
|
sysGatewayRouteService.deleteById(id);
|
||||||
@ -96,7 +96,7 @@ public class SysGatewayRouteController extends JeecgController<SysGatewayRoute,
|
|||||||
* @param jsonObject
|
* @param jsonObject
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:getway:putRecycleBin')")
|
@RequiresPermissions("system:gateway:putRecycleBin")
|
||||||
@RequestMapping(value = "/putRecycleBin", method = RequestMethod.PUT)
|
@RequestMapping(value = "/putRecycleBin", method = RequestMethod.PUT)
|
||||||
public Result putRecycleBin(@RequestBody JSONObject jsonObject, HttpServletRequest request) {
|
public Result putRecycleBin(@RequestBody JSONObject jsonObject, HttpServletRequest request) {
|
||||||
try {
|
try {
|
||||||
@ -117,7 +117,7 @@ public class SysGatewayRouteController extends JeecgController<SysGatewayRoute,
|
|||||||
* @param ids 被删除的路由ID,多个id用半角逗号分割
|
* @param ids 被删除的路由ID,多个id用半角逗号分割
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:getway:deleteRecycleBin')")
|
@RequiresPermissions("system:gateway:deleteRecycleBin")
|
||||||
@RequestMapping(value = "/deleteRecycleBin", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/deleteRecycleBin", method = RequestMethod.DELETE)
|
||||||
public Result deleteRecycleBin(@RequestParam("ids") String ids) {
|
public Result deleteRecycleBin(@RequestParam("ids") String ids) {
|
||||||
try {
|
try {
|
||||||
@ -136,7 +136,7 @@ public class SysGatewayRouteController extends JeecgController<SysGatewayRoute,
|
|||||||
* @param id 路由id
|
* @param id 路由id
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:getway:copyRoute')")
|
@RequiresPermissions("system:gateway:copyRoute")
|
||||||
@RequestMapping(value = "/copyRoute", method = RequestMethod.GET)
|
@RequestMapping(value = "/copyRoute", method = RequestMethod.GET)
|
||||||
public Result<SysGatewayRoute> copyRoute(@RequestParam(name = "id", required = true) String id, HttpServletRequest req) {
|
public Result<SysGatewayRoute> copyRoute(@RequestParam(name = "id", required = true) String id, HttpServletRequest req) {
|
||||||
Result<SysGatewayRoute> result = new Result<>();
|
Result<SysGatewayRoute> result = new Result<>();
|
||||||
|
|||||||
@ -7,13 +7,14 @@ import java.util.List;
|
|||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.system.base.controller.JeecgController;
|
import org.jeecg.common.system.base.controller.JeecgController;
|
||||||
import org.jeecg.common.system.query.QueryGenerator;
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.config.JeecgBaseConfig;
|
import org.jeecg.config.JeecgBaseConfig;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecg.modules.system.entity.SysLog;
|
import org.jeecg.modules.system.entity.SysLog;
|
||||||
import org.jeecg.modules.system.entity.SysRole;
|
import org.jeecg.modules.system.entity.SysRole;
|
||||||
import org.jeecg.modules.system.service.ISysLogService;
|
import org.jeecg.modules.system.service.ISysLogService;
|
||||||
@ -154,7 +155,7 @@ public class SysLogController extends JeecgController<SysLog, ISysLogService> {
|
|||||||
paramMap.remove("order");
|
paramMap.remove("order");
|
||||||
// 组装查询条件(已剔除排序参数)
|
// 组装查询条件(已剔除排序参数)
|
||||||
QueryWrapper<SysLog> queryWrapper = QueryGenerator.initQueryWrapper(syslog, paramMap);
|
QueryWrapper<SysLog> queryWrapper = QueryGenerator.initQueryWrapper(syslog, paramMap);
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
// 过滤选中数据
|
// 过滤选中数据
|
||||||
String selections = request.getParameter("selections");
|
String selections = request.getParameter("selections");
|
||||||
if (oConvertUtils.isNotEmpty(selections)) {
|
if (oConvertUtils.isNotEmpty(selections)) {
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
package org.jeecg.modules.system.controller;
|
package org.jeecg.modules.system.controller;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONArray;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
|
import org.apache.shiro.subject.Subject;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.constant.SymbolConstant;
|
import org.jeecg.common.constant.SymbolConstant;
|
||||||
@ -16,8 +16,7 @@ import org.jeecg.common.system.vo.LoginUser;
|
|||||||
import org.jeecg.common.util.Md5Util;
|
import org.jeecg.common.util.Md5Util;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.config.JeecgBaseConfig;
|
import org.jeecg.config.JeecgBaseConfig;
|
||||||
import org.jeecg.config.security.JeecgPermissionService;
|
import org.jeecg.config.shiro.ShiroRealm;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecg.modules.base.service.BaseCommonService;
|
import org.jeecg.modules.base.service.BaseCommonService;
|
||||||
import org.jeecg.modules.system.constant.DefIndexConst;
|
import org.jeecg.modules.system.constant.DefIndexConst;
|
||||||
import org.jeecg.modules.system.entity.*;
|
import org.jeecg.modules.system.entity.*;
|
||||||
@ -26,10 +25,9 @@ import org.jeecg.modules.system.model.TreeModel;
|
|||||||
import org.jeecg.modules.system.service.*;
|
import org.jeecg.modules.system.service.*;
|
||||||
import org.jeecg.modules.system.util.PermissionDataUtil;
|
import org.jeecg.modules.system.util.PermissionDataUtil;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -69,9 +67,9 @@ public class SysPermissionController {
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISysRoleIndexService sysRoleIndexService;
|
private ISysRoleIndexService sysRoleIndexService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private JeecgPermissionService jeecgPermissionService;
|
private ShiroRealm shiroRealm;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 子菜单
|
* 子菜单
|
||||||
@ -245,7 +243,7 @@ public class SysPermissionController {
|
|||||||
Result<JSONObject> result = new Result<JSONObject>();
|
Result<JSONObject> result = new Result<JSONObject>();
|
||||||
try {
|
try {
|
||||||
//直接获取当前用户不适用前端token
|
//直接获取当前用户不适用前端token
|
||||||
LoginUser loginUser = SecureUtil.currentUser();
|
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
if (oConvertUtils.isEmpty(loginUser)) {
|
if (oConvertUtils.isEmpty(loginUser)) {
|
||||||
return Result.error("请登录系统!");
|
return Result.error("请登录系统!");
|
||||||
}
|
}
|
||||||
@ -353,7 +351,7 @@ public class SysPermissionController {
|
|||||||
public Result<?> getPermCode() {
|
public Result<?> getPermCode() {
|
||||||
try {
|
try {
|
||||||
// 直接获取当前用户
|
// 直接获取当前用户
|
||||||
LoginUser loginUser = SecureUtil.currentUser();
|
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
if (oConvertUtils.isEmpty(loginUser)) {
|
if (oConvertUtils.isEmpty(loginUser)) {
|
||||||
return Result.error("请登录系统!");
|
return Result.error("请登录系统!");
|
||||||
}
|
}
|
||||||
@ -394,7 +392,7 @@ public class SysPermissionController {
|
|||||||
* @param permission
|
* @param permission
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:permission:add')")
|
@RequiresPermissions("system:permission:add")
|
||||||
@RequestMapping(value = "/add", method = RequestMethod.POST)
|
@RequestMapping(value = "/add", method = RequestMethod.POST)
|
||||||
public Result<SysPermission> add(@RequestBody SysPermission permission) {
|
public Result<SysPermission> add(@RequestBody SysPermission permission) {
|
||||||
Result<SysPermission> result = new Result<SysPermission>();
|
Result<SysPermission> result = new Result<SysPermission>();
|
||||||
@ -414,7 +412,7 @@ public class SysPermissionController {
|
|||||||
* @param permission
|
* @param permission
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:permission:edit')")
|
@RequiresPermissions("system:permission:edit")
|
||||||
@RequestMapping(value = "/edit", method = { RequestMethod.PUT, RequestMethod.POST })
|
@RequestMapping(value = "/edit", method = { RequestMethod.PUT, RequestMethod.POST })
|
||||||
public Result<SysPermission> edit(@RequestBody SysPermission permission) {
|
public Result<SysPermission> edit(@RequestBody SysPermission permission) {
|
||||||
Result<SysPermission> result = new Result<>();
|
Result<SysPermission> result = new Result<>();
|
||||||
@ -456,7 +454,7 @@ public class SysPermissionController {
|
|||||||
* @param id
|
* @param id
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:permission:delete')")
|
@RequiresPermissions("system:permission:delete")
|
||||||
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
|
||||||
public Result<SysPermission> delete(@RequestParam(name = "id", required = true) String id) {
|
public Result<SysPermission> delete(@RequestParam(name = "id", required = true) String id) {
|
||||||
Result<SysPermission> result = new Result<>();
|
Result<SysPermission> result = new Result<>();
|
||||||
@ -475,7 +473,7 @@ public class SysPermissionController {
|
|||||||
* @param ids
|
* @param ids
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:permission:deleteBatch')")
|
@RequiresPermissions("system:permission:deleteBatch")
|
||||||
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
|
||||||
public Result<SysPermission> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
public Result<SysPermission> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
||||||
Result<SysPermission> result = new Result<>();
|
Result<SysPermission> result = new Result<>();
|
||||||
@ -583,7 +581,7 @@ public class SysPermissionController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@RequestMapping(value = "/saveRolePermission", method = RequestMethod.POST)
|
@RequestMapping(value = "/saveRolePermission", method = RequestMethod.POST)
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:permission:saveRole')")
|
@RequiresPermissions("system:permission:saveRole")
|
||||||
public Result<String> saveRolePermission(@RequestBody JSONObject json) {
|
public Result<String> saveRolePermission(@RequestBody JSONObject json) {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
Result<String> result = new Result<>();
|
Result<String> result = new Result<>();
|
||||||
@ -592,14 +590,18 @@ public class SysPermissionController {
|
|||||||
String permissionIds = json.getString("permissionIds");
|
String permissionIds = json.getString("permissionIds");
|
||||||
String lastPermissionIds = json.getString("lastpermissionIds");
|
String lastPermissionIds = json.getString("lastpermissionIds");
|
||||||
this.sysRolePermissionService.saveRolePermission(roleId, permissionIds, lastPermissionIds);
|
this.sysRolePermissionService.saveRolePermission(roleId, permissionIds, lastPermissionIds);
|
||||||
//update-begin---author:wangshuai ---date:20220316 for:[VUEN-234]用户管理角色授权添加敏感日志------------
|
// 代码逻辑说明: [VUEN-234]用户管理角色授权添加敏感日志------------
|
||||||
LoginUser loginUser = SecureUtil.currentUser();
|
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
baseCommonService.addLog("修改角色ID: "+roleId+" 的权限配置,操作人: " +loginUser.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
|
baseCommonService.addLog("修改角色ID: "+roleId+" 的权限配置,操作人: " +loginUser.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
|
||||||
//update-end---author:wangshuai ---date:20220316 for:[VUEN-234]用户管理角色授权添加敏感日志------------
|
|
||||||
// 清除权限缓存
|
|
||||||
jeecgPermissionService.clearCache();
|
|
||||||
result.success("保存成功!");
|
result.success("保存成功!");
|
||||||
log.info("======角色授权成功=====耗时:" + (System.currentTimeMillis() - start) + "毫秒");
|
log.info("======角色授权成功=====耗时:" + (System.currentTimeMillis() - start) + "毫秒");
|
||||||
|
|
||||||
|
// 清除当前用户的授权缓存信息
|
||||||
|
Subject currentUser = SecurityUtils.getSubject();
|
||||||
|
if (currentUser.isAuthenticated()) {
|
||||||
|
shiroRealm.clearCache(currentUser.getPrincipals());
|
||||||
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
result.error500("授权失败!");
|
result.error500("授权失败!");
|
||||||
log.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
@ -911,7 +913,7 @@ public class SysPermissionController {
|
|||||||
* @param sysPermissionDataRule
|
* @param sysPermissionDataRule
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:permission:addRule')")
|
@RequiresPermissions("system:permission:addRule")
|
||||||
@RequestMapping(value = "/addPermissionRule", method = RequestMethod.POST)
|
@RequestMapping(value = "/addPermissionRule", method = RequestMethod.POST)
|
||||||
public Result<SysPermissionDataRule> addPermissionRule(@RequestBody SysPermissionDataRule sysPermissionDataRule) {
|
public Result<SysPermissionDataRule> addPermissionRule(@RequestBody SysPermissionDataRule sysPermissionDataRule) {
|
||||||
Result<SysPermissionDataRule> result = new Result<SysPermissionDataRule>();
|
Result<SysPermissionDataRule> result = new Result<SysPermissionDataRule>();
|
||||||
@ -926,7 +928,7 @@ public class SysPermissionController {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:permission:editRule')")
|
@RequiresPermissions("system:permission:editRule")
|
||||||
@RequestMapping(value = "/editPermissionRule", method = { RequestMethod.PUT, RequestMethod.POST })
|
@RequestMapping(value = "/editPermissionRule", method = { RequestMethod.PUT, RequestMethod.POST })
|
||||||
public Result<SysPermissionDataRule> editPermissionRule(@RequestBody SysPermissionDataRule sysPermissionDataRule) {
|
public Result<SysPermissionDataRule> editPermissionRule(@RequestBody SysPermissionDataRule sysPermissionDataRule) {
|
||||||
Result<SysPermissionDataRule> result = new Result<SysPermissionDataRule>();
|
Result<SysPermissionDataRule> result = new Result<SysPermissionDataRule>();
|
||||||
@ -946,7 +948,7 @@ public class SysPermissionController {
|
|||||||
* @param id
|
* @param id
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:permission:deleteRule')")
|
@RequiresPermissions("system:permission:deleteRule")
|
||||||
@RequestMapping(value = "/deletePermissionRule", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/deletePermissionRule", method = RequestMethod.DELETE)
|
||||||
public Result<SysPermissionDataRule> deletePermissionRule(@RequestParam(name = "id", required = true) String id) {
|
public Result<SysPermissionDataRule> deletePermissionRule(@RequestParam(name = "id", required = true) String id) {
|
||||||
Result<SysPermissionDataRule> result = new Result<SysPermissionDataRule>();
|
Result<SysPermissionDataRule> result = new Result<SysPermissionDataRule>();
|
||||||
@ -1003,7 +1005,7 @@ public class SysPermissionController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@RequestMapping(value = "/saveDepartPermission", method = RequestMethod.POST)
|
@RequestMapping(value = "/saveDepartPermission", method = RequestMethod.POST)
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:permission:saveDepart')")
|
@RequiresPermissions("system:permission:saveDepart")
|
||||||
public Result<String> saveDepartPermission(@RequestBody JSONObject json) {
|
public Result<String> saveDepartPermission(@RequestBody JSONObject json) {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
Result<String> result = new Result<>();
|
Result<String> result = new Result<>();
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.aspect.annotation.AutoLog;
|
import org.jeecg.common.aspect.annotation.AutoLog;
|
||||||
import org.jeecg.common.config.TenantContext;
|
import org.jeecg.common.config.TenantContext;
|
||||||
@ -17,7 +18,6 @@ import org.jeecg.common.system.vo.LoginUser;
|
|||||||
import org.jeecg.common.util.ImportExcelUtil;
|
import org.jeecg.common.util.ImportExcelUtil;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecg.modules.system.entity.SysPosition;
|
import org.jeecg.modules.system.entity.SysPosition;
|
||||||
import org.jeecg.modules.system.entity.SysUser;
|
import org.jeecg.modules.system.entity.SysUser;
|
||||||
import org.jeecg.modules.system.service.ISysPositionService;
|
import org.jeecg.modules.system.service.ISysPositionService;
|
||||||
@ -30,7 +30,6 @@ import org.jeecgframework.poi.excel.entity.ImportParams;
|
|||||||
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
|
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
|
||||||
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
|
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||||
@ -248,7 +247,7 @@ public class SysPositionController {
|
|||||||
//Step.2 AutoPoi 导出Excel
|
//Step.2 AutoPoi 导出Excel
|
||||||
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
|
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
|
||||||
List<SysPosition> pageList = sysPositionService.list(queryWrapper);
|
List<SysPosition> pageList = sysPositionService.list(queryWrapper);
|
||||||
LoginUser user = SecureUtil.currentUser();
|
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
//导出文件名称
|
//导出文件名称
|
||||||
mv.addObject(NormalExcelConstants.FILE_NAME, "职务表列表");
|
mv.addObject(NormalExcelConstants.FILE_NAME, "职务表列表");
|
||||||
mv.addObject(NormalExcelConstants.CLASS, SysPosition.class);
|
mv.addObject(NormalExcelConstants.CLASS, SysPosition.class);
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
package org.jeecg.modules.system.controller;
|
package org.jeecg.modules.system.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -13,6 +15,7 @@ import jakarta.servlet.http.HttpServletResponse;
|
|||||||
|
|
||||||
import cn.hutool.core.util.RandomUtil;
|
import cn.hutool.core.util.RandomUtil;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.base.BaseMap;
|
import org.jeecg.common.base.BaseMap;
|
||||||
import org.jeecg.common.config.TenantContext;
|
import org.jeecg.common.config.TenantContext;
|
||||||
@ -22,7 +25,6 @@ import org.jeecg.common.modules.redis.client.JeecgRedisClient;
|
|||||||
import org.jeecg.common.system.query.QueryGenerator;
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecg.modules.base.service.BaseCommonService;
|
import org.jeecg.modules.base.service.BaseCommonService;
|
||||||
import org.jeecg.modules.system.entity.*;
|
import org.jeecg.modules.system.entity.*;
|
||||||
import org.jeecg.modules.system.model.TreeModel;
|
import org.jeecg.modules.system.model.TreeModel;
|
||||||
@ -35,7 +37,6 @@ import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
|
|||||||
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
|
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -48,6 +49,7 @@ import org.springframework.web.multipart.MultipartFile;
|
|||||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
@ -95,7 +97,7 @@ public class SysRoleController {
|
|||||||
* @param req
|
* @param req
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:role:list')")
|
@RequiresPermissions("system:role:list")
|
||||||
@RequestMapping(value = "/list", method = RequestMethod.GET)
|
@RequestMapping(value = "/list", method = RequestMethod.GET)
|
||||||
public Result<IPage<SysRole>> queryPageList(SysRole role,
|
public Result<IPage<SysRole>> queryPageList(SysRole role,
|
||||||
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
|
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
|
||||||
@ -150,7 +152,7 @@ public class SysRoleController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@RequestMapping(value = "/add", method = RequestMethod.POST)
|
@RequestMapping(value = "/add", method = RequestMethod.POST)
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:role:add')")
|
@RequiresPermissions("system:role:add")
|
||||||
public Result<SysRole> add(@RequestBody SysRole role) {
|
public Result<SysRole> add(@RequestBody SysRole role) {
|
||||||
Result<SysRole> result = new Result<SysRole>();
|
Result<SysRole> result = new Result<SysRole>();
|
||||||
try {
|
try {
|
||||||
@ -174,7 +176,7 @@ public class SysRoleController {
|
|||||||
* @param role
|
* @param role
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:role:edit')")
|
@RequiresPermissions("system:role:edit")
|
||||||
@RequestMapping(value = "/edit",method = {RequestMethod.PUT,RequestMethod.POST})
|
@RequestMapping(value = "/edit",method = {RequestMethod.PUT,RequestMethod.POST})
|
||||||
public Result<SysRole> edit(@RequestBody SysRole role) {
|
public Result<SysRole> edit(@RequestBody SysRole role) {
|
||||||
Result<SysRole> result = new Result<SysRole>();
|
Result<SysRole> result = new Result<SysRole>();
|
||||||
@ -188,7 +190,7 @@ public class SysRoleController {
|
|||||||
//如果是saas隔离的情况下,判断当前租户id是否是当前租户下的
|
//如果是saas隔离的情况下,判断当前租户id是否是当前租户下的
|
||||||
if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
|
if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
|
||||||
//获取当前用户
|
//获取当前用户
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
Integer tenantId = oConvertUtils.getInt(TenantContext.getTenant(), 0);
|
Integer tenantId = oConvertUtils.getInt(TenantContext.getTenant(), 0);
|
||||||
String username = "admin";
|
String username = "admin";
|
||||||
if (!tenantId.equals(sysrole.getTenantId()) && !username.equals(sysUser.getUsername())) {
|
if (!tenantId.equals(sysrole.getTenantId()) && !username.equals(sysUser.getUsername())) {
|
||||||
@ -211,13 +213,13 @@ public class SysRoleController {
|
|||||||
* @param id
|
* @param id
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:role:delete')")
|
@RequiresPermissions("system:role:delete")
|
||||||
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
|
||||||
public Result<?> delete(@RequestParam(name="id",required=true) String id) {
|
public Result<?> delete(@RequestParam(name="id",required=true) String id) {
|
||||||
//如果是saas隔离的情况下,判断当前租户id是否是当前租户下的
|
//如果是saas隔离的情况下,判断当前租户id是否是当前租户下的
|
||||||
if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL){
|
if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL){
|
||||||
//获取当前用户
|
//获取当前用户
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
int tenantId = oConvertUtils.getInt(TenantContext.getTenant(), 0);
|
int tenantId = oConvertUtils.getInt(TenantContext.getTenant(), 0);
|
||||||
Long getRoleCount = sysRoleService.getRoleCountByTenantId(id, tenantId);
|
Long getRoleCount = sysRoleService.getRoleCountByTenantId(id, tenantId);
|
||||||
String username = "admin";
|
String username = "admin";
|
||||||
@ -240,7 +242,7 @@ public class SysRoleController {
|
|||||||
* @param ids
|
* @param ids
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:role:deleteBatch')")
|
@RequiresPermissions("system:role:deleteBatch")
|
||||||
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
|
||||||
public Result<SysRole> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
|
public Result<SysRole> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
|
||||||
baseCommonService.addLog("删除角色操作,角色ids:" + ids, CommonConstant.LOG_TYPE_2, CommonConstant.OPERATE_TYPE_4);
|
baseCommonService.addLog("删除角色操作,角色ids:" + ids, CommonConstant.LOG_TYPE_2, CommonConstant.OPERATE_TYPE_4);
|
||||||
@ -252,7 +254,7 @@ public class SysRoleController {
|
|||||||
if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL){
|
if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL){
|
||||||
int tenantId = oConvertUtils.getInt(TenantContext.getTenant(), 0);
|
int tenantId = oConvertUtils.getInt(TenantContext.getTenant(), 0);
|
||||||
String[] roleIds = ids.split(SymbolConstant.COMMA);
|
String[] roleIds = ids.split(SymbolConstant.COMMA);
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
String username = "admin";
|
String username = "admin";
|
||||||
for (String id:roleIds) {
|
for (String id:roleIds) {
|
||||||
Long getRoleCount = sysRoleService.getRoleCountByTenantId(id, tenantId);
|
Long getRoleCount = sysRoleService.getRoleCountByTenantId(id, tenantId);
|
||||||
@ -319,7 +321,7 @@ public class SysRoleController {
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:role:queryallNoByTenant')")
|
@RequiresPermissions("system:role:queryallNoByTenant")
|
||||||
@RequestMapping(value = "/queryallNoByTenant", method = RequestMethod.GET)
|
@RequestMapping(value = "/queryallNoByTenant", method = RequestMethod.GET)
|
||||||
public Result<List<SysRole>> queryallNoByTenant() {
|
public Result<List<SysRole>> queryallNoByTenant() {
|
||||||
Result<List<SysRole>> result = new Result<>();
|
Result<List<SysRole>> result = new Result<>();
|
||||||
@ -395,7 +397,7 @@ public class SysRoleController {
|
|||||||
//导出文件名称
|
//导出文件名称
|
||||||
mv.addObject(NormalExcelConstants.FILE_NAME,"角色列表");
|
mv.addObject(NormalExcelConstants.FILE_NAME,"角色列表");
|
||||||
mv.addObject(NormalExcelConstants.CLASS,SysRole.class);
|
mv.addObject(NormalExcelConstants.CLASS,SysRole.class);
|
||||||
LoginUser user = SecureUtil.currentUser();
|
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
//导出支持xlsx
|
//导出支持xlsx
|
||||||
mv.addObject(NormalExcelConstants.PARAMS,new ExportParams("角色列表数据","导出人:"+user.getRealname(),"导出信息", ExcelType.XSSF));
|
mv.addObject(NormalExcelConstants.PARAMS,new ExportParams("角色列表数据","导出人:"+user.getRealname(),"导出信息", ExcelType.XSSF));
|
||||||
mv.addObject(NormalExcelConstants.DATA_LIST,pageList);
|
mv.addObject(NormalExcelConstants.DATA_LIST,pageList);
|
||||||
|
|||||||
@ -1,13 +1,15 @@
|
|||||||
package org.jeecg.modules.system.controller;
|
package org.jeecg.modules.system.controller;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.aspect.annotation.AutoLog;
|
import org.jeecg.common.aspect.annotation.AutoLog;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
@ -19,19 +21,10 @@ import org.jeecg.common.util.RedisUtil;
|
|||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.modules.base.service.BaseCommonService;
|
import org.jeecg.modules.base.service.BaseCommonService;
|
||||||
import org.jeecg.modules.system.constant.DefIndexConst;
|
import org.jeecg.modules.system.constant.DefIndexConst;
|
||||||
import org.jeecg.common.aspect.annotation.AutoLog;
|
|
||||||
import org.jeecg.modules.system.entity.SysRoleIndex;
|
import org.jeecg.modules.system.entity.SysRoleIndex;
|
||||||
import org.jeecg.modules.system.service.ISysRoleIndexService;
|
import org.jeecg.modules.system.service.ISysRoleIndexService;
|
||||||
import org.jeecg.modules.system.service.ISysUserService;
|
import org.jeecg.modules.system.service.ISysUserService;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.jeecg.common.system.base.controller.JeecgController;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
@ -87,7 +80,7 @@ public class SysRoleIndexController extends JeecgController<SysRoleIndex, ISysRo
|
|||||||
* @param sysRoleIndex
|
* @param sysRoleIndex
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:roleindex:add')")
|
@RequiresPermissions("system:roleindex:add")
|
||||||
@AutoLog(value = "角色首页配置-添加")
|
@AutoLog(value = "角色首页配置-添加")
|
||||||
@Operation(summary = "角色首页配置-添加")
|
@Operation(summary = "角色首页配置-添加")
|
||||||
@PostMapping(value = "/add")
|
@PostMapping(value = "/add")
|
||||||
@ -110,7 +103,7 @@ public class SysRoleIndexController extends JeecgController<SysRoleIndex, ISysRo
|
|||||||
* @param sysRoleIndex
|
* @param sysRoleIndex
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:roleindex:edit')")
|
@RequiresPermissions("system:roleindex:edit")
|
||||||
@AutoLog(value = "角色首页配置-编辑")
|
@AutoLog(value = "角色首页配置-编辑")
|
||||||
@Operation(summary = "角色首页配置-编辑")
|
@Operation(summary = "角色首页配置-编辑")
|
||||||
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
|
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
|
||||||
@ -135,7 +128,7 @@ public class SysRoleIndexController extends JeecgController<SysRoleIndex, ISysRo
|
|||||||
*/
|
*/
|
||||||
@AutoLog(value = "角色首页配置-通过id删除")
|
@AutoLog(value = "角色首页配置-通过id删除")
|
||||||
@Operation(summary = "角色首页配置-通过id删除")
|
@Operation(summary = "角色首页配置-通过id删除")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:roleindex:delete')")
|
@RequiresPermissions("system:roleindex:delete")
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
|
public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
|
||||||
sysRoleIndexService.removeById(id);
|
sysRoleIndexService.removeById(id);
|
||||||
@ -150,7 +143,7 @@ public class SysRoleIndexController extends JeecgController<SysRoleIndex, ISysRo
|
|||||||
*/
|
*/
|
||||||
@AutoLog(value = "角色首页配置-批量删除")
|
@AutoLog(value = "角色首页配置-批量删除")
|
||||||
@Operation(summary = "角色首页配置-批量删除")
|
@Operation(summary = "角色首页配置-批量删除")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:roleindex:deleteBatch')")
|
@RequiresPermissions("system:roleindex:deleteBatch")
|
||||||
@DeleteMapping(value = "/deleteBatch")
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
public Result<?> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
public Result<?> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
||||||
baseCommonService.addLog("批量删除用户, ids: " +ids ,CommonConstant.LOG_TYPE_2, 3);
|
baseCommonService.addLog("批量删除用户, ids: " +ids ,CommonConstant.LOG_TYPE_2, 3);
|
||||||
@ -222,7 +215,7 @@ public class SysRoleIndexController extends JeecgController<SysRoleIndex, ISysRo
|
|||||||
/**
|
/**
|
||||||
* 更新默认首页配置
|
* 更新默认首页配置
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:permission:setDefIndex')")
|
@RequiresPermissions("system:permission:setDefIndex")
|
||||||
@PutMapping("/updateDefIndex")
|
@PutMapping("/updateDefIndex")
|
||||||
public Result<?> updateDefIndex(
|
public Result<?> updateDefIndex(
|
||||||
@RequestParam("url") String url,
|
@RequestParam("url") String url,
|
||||||
|
|||||||
@ -3,10 +3,11 @@ package org.jeecg.modules.system.controller;
|
|||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.aspect.annotation.AutoLog;
|
import org.jeecg.common.aspect.annotation.AutoLog;
|
||||||
import org.jeecg.common.system.base.controller.JeecgController;
|
import org.jeecg.common.system.base.controller.JeecgController;
|
||||||
@ -14,7 +15,6 @@ import org.jeecg.common.system.query.QueryGenerator;
|
|||||||
import org.jeecg.modules.system.entity.SysTableWhiteList;
|
import org.jeecg.modules.system.entity.SysTableWhiteList;
|
||||||
import org.jeecg.modules.system.service.ISysTableWhiteListService;
|
import org.jeecg.modules.system.service.ISysTableWhiteListService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
@ -44,7 +44,7 @@ public class SysTableWhiteListController extends JeecgController<SysTableWhiteLi
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
//@RequiresRoles("admin")
|
//@RequiresRoles("admin")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tableWhite:list')")
|
@RequiresPermissions("system:tableWhite:list")
|
||||||
@GetMapping(value = "/list")
|
@GetMapping(value = "/list")
|
||||||
public Result<?> queryPageList(
|
public Result<?> queryPageList(
|
||||||
SysTableWhiteList sysTableWhiteList,
|
SysTableWhiteList sysTableWhiteList,
|
||||||
@ -67,7 +67,7 @@ public class SysTableWhiteListController extends JeecgController<SysTableWhiteLi
|
|||||||
@AutoLog(value = "系统表白名单-添加")
|
@AutoLog(value = "系统表白名单-添加")
|
||||||
@Operation(summary = "系统表白名单-添加")
|
@Operation(summary = "系统表白名单-添加")
|
||||||
//@RequiresRoles("admin")
|
//@RequiresRoles("admin")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tableWhite:add')")
|
@RequiresPermissions("system:tableWhite:add")
|
||||||
@PostMapping(value = "/add")
|
@PostMapping(value = "/add")
|
||||||
public Result<?> add(@RequestBody SysTableWhiteList sysTableWhiteList) {
|
public Result<?> add(@RequestBody SysTableWhiteList sysTableWhiteList) {
|
||||||
if (sysTableWhiteListService.add(sysTableWhiteList)) {
|
if (sysTableWhiteListService.add(sysTableWhiteList)) {
|
||||||
@ -84,9 +84,9 @@ public class SysTableWhiteListController extends JeecgController<SysTableWhiteLi
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@AutoLog(value = "系统表白名单-编辑")
|
@AutoLog(value = "系统表白名单-编辑")
|
||||||
@Operation(summary = "系统表白名单-编辑")
|
@Operation(summary = "系统表白名单-编辑")
|
||||||
//@RequiresRoles("admin")
|
//@RequiresRoles("admin")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tableWhite:edit')")
|
@RequiresPermissions("system:tableWhite:edit")
|
||||||
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
|
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
|
||||||
public Result<?> edit(@RequestBody SysTableWhiteList sysTableWhiteList) {
|
public Result<?> edit(@RequestBody SysTableWhiteList sysTableWhiteList) {
|
||||||
if (sysTableWhiteListService.edit(sysTableWhiteList)) {
|
if (sysTableWhiteListService.edit(sysTableWhiteList)) {
|
||||||
@ -105,7 +105,7 @@ public class SysTableWhiteListController extends JeecgController<SysTableWhiteLi
|
|||||||
@AutoLog(value = "系统表白名单-通过id删除")
|
@AutoLog(value = "系统表白名单-通过id删除")
|
||||||
@Operation(summary = "系统表白名单-通过id删除")
|
@Operation(summary = "系统表白名单-通过id删除")
|
||||||
// @RequiresRoles("admin")
|
// @RequiresRoles("admin")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tableWhite:delete')")
|
@RequiresPermissions("system:tableWhite:delete")
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
public Result<?> delete(@RequestParam(name = "id") String id) {
|
public Result<?> delete(@RequestParam(name = "id") String id) {
|
||||||
if (sysTableWhiteListService.deleteByIds(id)) {
|
if (sysTableWhiteListService.deleteByIds(id)) {
|
||||||
@ -122,9 +122,9 @@ public class SysTableWhiteListController extends JeecgController<SysTableWhiteLi
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@AutoLog(value = "系统表白名单-批量删除")
|
@AutoLog(value = "系统表白名单-批量删除")
|
||||||
@Operation(summary = "系统表白名单-批量删除")
|
@Operation(summary = "系统表白名单-批量删除")
|
||||||
// @RequiresRoles("admin")
|
// @RequiresRoles("admin")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tableWhite:deleteBatch')")
|
@RequiresPermissions("system:tableWhite:deleteBatch")
|
||||||
@DeleteMapping(value = "/deleteBatch")
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
public Result<?> deleteBatch(@RequestParam(name = "ids") String ids) {
|
public Result<?> deleteBatch(@RequestParam(name = "ids") String ids) {
|
||||||
if (sysTableWhiteListService.deleteByIds(ids)) {
|
if (sysTableWhiteListService.deleteByIds(ids)) {
|
||||||
@ -143,7 +143,7 @@ public class SysTableWhiteListController extends JeecgController<SysTableWhiteLi
|
|||||||
@AutoLog(value = "系统表白名单-通过id查询")
|
@AutoLog(value = "系统表白名单-通过id查询")
|
||||||
@Operation(summary = "系统表白名单-通过id查询")
|
@Operation(summary = "系统表白名单-通过id查询")
|
||||||
// @RequiresRoles("admin")
|
// @RequiresRoles("admin")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tableWhite:queryById')")
|
@RequiresPermissions("system:tableWhite:queryById")
|
||||||
@GetMapping(value = "/queryById")
|
@GetMapping(value = "/queryById")
|
||||||
public Result<?> queryById(@RequestParam(name = "id", required = true) String id) {
|
public Result<?> queryById(@RequestParam(name = "id", required = true) String id) {
|
||||||
SysTableWhiteList sysTableWhiteList = sysTableWhiteListService.getById(id);
|
SysTableWhiteList sysTableWhiteList = sysTableWhiteListService.getById(id);
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
|||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.aspect.annotation.PermissionData;
|
import org.jeecg.common.aspect.annotation.PermissionData;
|
||||||
import org.jeecg.common.config.TenantContext;
|
import org.jeecg.common.config.TenantContext;
|
||||||
@ -20,7 +21,7 @@ import org.jeecg.common.util.PasswordUtil;
|
|||||||
import org.jeecg.common.util.TokenUtils;
|
import org.jeecg.common.util.TokenUtils;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
import org.jeecg.config.sign.annotation.SignatureCheck;
|
||||||
import org.jeecg.modules.base.service.BaseCommonService;
|
import org.jeecg.modules.base.service.BaseCommonService;
|
||||||
import org.jeecg.modules.system.entity.*;
|
import org.jeecg.modules.system.entity.*;
|
||||||
import org.jeecg.modules.system.service.ISysTenantPackService;
|
import org.jeecg.modules.system.service.ISysTenantPackService;
|
||||||
@ -34,7 +35,6 @@ import org.jeecg.modules.system.vo.tenant.TenantPackModel;
|
|||||||
import org.jeecg.modules.system.vo.tenant.TenantPackUser;
|
import org.jeecg.modules.system.vo.tenant.TenantPackUser;
|
||||||
import org.jeecg.modules.system.vo.tenant.TenantPackUserCount;
|
import org.jeecg.modules.system.vo.tenant.TenantPackUserCount;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
@ -75,7 +75,7 @@ public class SysTenantController {
|
|||||||
* @param req
|
* @param req
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tenant:list')")
|
@RequiresPermissions("system:tenant:list")
|
||||||
@PermissionData(pageComponent = "system/TenantList")
|
@PermissionData(pageComponent = "system/TenantList")
|
||||||
@RequestMapping(value = "/list", method = RequestMethod.GET)
|
@RequestMapping(value = "/list", method = RequestMethod.GET)
|
||||||
public Result<IPage<SysTenant>> queryPageList(SysTenant sysTenant,@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
|
public Result<IPage<SysTenant>> queryPageList(SysTenant sysTenant,@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
|
||||||
@ -114,7 +114,7 @@ public class SysTenantController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@GetMapping("/recycleBinPageList")
|
@GetMapping("/recycleBinPageList")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tenant:recycleBinPageList')")
|
@RequiresPermissions("system:tenant:recycleBinPageList")
|
||||||
public Result<IPage<SysTenant>> recycleBinPageList(SysTenant sysTenant,@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
|
public Result<IPage<SysTenant>> recycleBinPageList(SysTenant sysTenant,@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
|
||||||
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,HttpServletRequest req){
|
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,HttpServletRequest req){
|
||||||
Result<IPage<SysTenant>> result = new Result<IPage<SysTenant>>();
|
Result<IPage<SysTenant>> result = new Result<IPage<SysTenant>>();
|
||||||
@ -130,7 +130,7 @@ public class SysTenantController {
|
|||||||
* @param
|
* @param
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tenant:add')")
|
@RequiresPermissions("system:tenant:add")
|
||||||
@RequestMapping(value = "/add", method = RequestMethod.POST)
|
@RequestMapping(value = "/add", method = RequestMethod.POST)
|
||||||
public Result<SysTenant> add(@RequestBody SysTenant sysTenant) {
|
public Result<SysTenant> add(@RequestBody SysTenant sysTenant) {
|
||||||
Result<SysTenant> result = new Result();
|
Result<SysTenant> result = new Result();
|
||||||
@ -156,7 +156,7 @@ public class SysTenantController {
|
|||||||
* @author chenrui
|
* @author chenrui
|
||||||
* @date 2025/2/6 18:24
|
* @date 2025/2/6 18:24
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tenant:syncDefaultPack')")
|
@RequiresPermissions("system:tenant:syncDefaultPack")
|
||||||
@PostMapping(value = "/syncDefaultPack")
|
@PostMapping(value = "/syncDefaultPack")
|
||||||
public Result<?> syncDefaultPack(@RequestParam(name="tenantId",required=true) Integer tenantId) {
|
public Result<?> syncDefaultPack(@RequestParam(name="tenantId",required=true) Integer tenantId) {
|
||||||
//同步默认产品包
|
//同步默认产品包
|
||||||
@ -169,7 +169,7 @@ public class SysTenantController {
|
|||||||
* @param
|
* @param
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tenant:edit')")
|
@RequiresPermissions("system:tenant:edit")
|
||||||
@RequestMapping(value = "/edit", method ={RequestMethod.PUT, RequestMethod.POST})
|
@RequestMapping(value = "/edit", method ={RequestMethod.PUT, RequestMethod.POST})
|
||||||
public Result<SysTenant> edit(@RequestBody SysTenant tenant) {
|
public Result<SysTenant> edit(@RequestBody SysTenant tenant) {
|
||||||
Result<SysTenant> result = new Result();
|
Result<SysTenant> result = new Result();
|
||||||
@ -192,14 +192,14 @@ public class SysTenantController {
|
|||||||
* @param id
|
* @param id
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tenant:delete')")
|
@RequiresPermissions("system:tenant:delete")
|
||||||
@RequestMapping(value = "/delete", method ={RequestMethod.DELETE, RequestMethod.POST})
|
@RequestMapping(value = "/delete", method ={RequestMethod.DELETE, RequestMethod.POST})
|
||||||
public Result<?> delete(@RequestParam(name="id",required=true) String id) {
|
public Result<?> delete(@RequestParam(name="id",required=true) String id) {
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
//如果是saas隔离的情况下,判断当前租户id是否是当前租户下的
|
//如果是saas隔离的情况下,判断当前租户id是否是当前租户下的
|
||||||
if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
|
if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
|
||||||
//获取当前用户
|
//获取当前用户
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
SysTenant sysTenant = sysTenantService.getById(id);
|
SysTenant sysTenant = sysTenantService.getById(id);
|
||||||
|
|
||||||
String username = "admin";
|
String username = "admin";
|
||||||
@ -220,7 +220,7 @@ public class SysTenantController {
|
|||||||
* @param ids
|
* @param ids
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tenant:deleteBatch')")
|
@RequiresPermissions("system:tenant:deleteBatch")
|
||||||
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
|
||||||
public Result<?> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
|
public Result<?> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
|
||||||
Result<?> result = new Result<>();
|
Result<?> result = new Result<>();
|
||||||
@ -235,7 +235,7 @@ public class SysTenantController {
|
|||||||
//如果是saas隔离的情况下,判断当前租户id是否是当前租户下的
|
//如果是saas隔离的情况下,判断当前租户id是否是当前租户下的
|
||||||
if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
|
if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
|
||||||
//获取当前用户
|
//获取当前用户
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
SysTenant sysTenant = sysTenantService.getById(id);
|
SysTenant sysTenant = sysTenantService.getById(id);
|
||||||
|
|
||||||
String username = "admin";
|
String username = "admin";
|
||||||
@ -261,6 +261,7 @@ public class SysTenantController {
|
|||||||
* @param id
|
* @param id
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
@SignatureCheck
|
||||||
@RequestMapping(value = "/queryById", method = RequestMethod.GET)
|
@RequestMapping(value = "/queryById", method = RequestMethod.GET)
|
||||||
public Result<SysTenant> queryById(@RequestParam(name="id",required=true) String id) {
|
public Result<SysTenant> queryById(@RequestParam(name="id",required=true) String id) {
|
||||||
Result<SysTenant> result = new Result<SysTenant>();
|
Result<SysTenant> result = new Result<SysTenant>();
|
||||||
@ -269,7 +270,7 @@ public class SysTenantController {
|
|||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------
|
||||||
//获取登录用户信息
|
//获取登录用户信息
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
//是否开启系统管理模块的多租户数据隔离【SAAS多租户模式】, admin给特权可以管理所有租户
|
//是否开启系统管理模块的多租户数据隔离【SAAS多租户模式】, admin给特权可以管理所有租户
|
||||||
if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL && !"admin".equals(sysUser.getUsername())){
|
if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL && !"admin".equals(sysUser.getUsername())){
|
||||||
Integer loginSessionTenant = oConvertUtils.getInt(TenantContext.getTenant());
|
Integer loginSessionTenant = oConvertUtils.getInt(TenantContext.getTenant());
|
||||||
@ -294,7 +295,7 @@ public class SysTenantController {
|
|||||||
* 查询有效的 租户数据
|
* 查询有效的 租户数据
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tenant:queryList')")
|
@RequiresPermissions("system:tenant:queryList")
|
||||||
@RequestMapping(value = "/queryList", method = RequestMethod.GET)
|
@RequestMapping(value = "/queryList", method = RequestMethod.GET)
|
||||||
public Result<List<SysTenant>> queryList(@RequestParam(name="ids",required=false) String ids) {
|
public Result<List<SysTenant>> queryList(@RequestParam(name="ids",required=false) String ids) {
|
||||||
Result<List<SysTenant>> result = new Result<List<SysTenant>>();
|
Result<List<SysTenant>> result = new Result<List<SysTenant>>();
|
||||||
@ -320,7 +321,7 @@ public class SysTenantController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@GetMapping(value = "/packList")
|
@GetMapping(value = "/packList")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tenant:packList')")
|
@RequiresPermissions("system:tenant:packList")
|
||||||
public Result<IPage<SysTenantPack>> queryPackPageList(SysTenantPack sysTenantPack,
|
public Result<IPage<SysTenantPack>> queryPackPageList(SysTenantPack sysTenantPack,
|
||||||
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
|
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
|
||||||
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
|
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
|
||||||
@ -342,7 +343,7 @@ public class SysTenantController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PostMapping(value = "/addPackPermission")
|
@PostMapping(value = "/addPackPermission")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tenant:add:pack')")
|
@RequiresPermissions("system:tenant:add:pack")
|
||||||
public Result<String> addPackPermission(@RequestBody SysTenantPack sysTenantPack) {
|
public Result<String> addPackPermission(@RequestBody SysTenantPack sysTenantPack) {
|
||||||
sysTenantPackService.addPackPermission(sysTenantPack);
|
sysTenantPackService.addPackPermission(sysTenantPack);
|
||||||
return Result.ok("创建租户产品包成功");
|
return Result.ok("创建租户产品包成功");
|
||||||
@ -355,7 +356,7 @@ public class SysTenantController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PutMapping(value = "/editPackPermission")
|
@PutMapping(value = "/editPackPermission")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tenant:edit:pack')")
|
@RequiresPermissions("system:tenant:edit:pack")
|
||||||
public Result<String> editPackPermission(@RequestBody SysTenantPack sysTenantPack) {
|
public Result<String> editPackPermission(@RequestBody SysTenantPack sysTenantPack) {
|
||||||
sysTenantPackService.editPackPermission(sysTenantPack);
|
sysTenantPackService.editPackPermission(sysTenantPack);
|
||||||
return Result.ok("修改租户产品包成功");
|
return Result.ok("修改租户产品包成功");
|
||||||
@ -368,7 +369,7 @@ public class SysTenantController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@DeleteMapping("/deleteTenantPack")
|
@DeleteMapping("/deleteTenantPack")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tenant:delete:pack')")
|
@RequiresPermissions("system:tenant:delete:pack")
|
||||||
public Result<String> deleteTenantPack(@RequestParam(value = "ids") String ids) {
|
public Result<String> deleteTenantPack(@RequestParam(value = "ids") String ids) {
|
||||||
sysTenantPackService.deleteTenantPack(ids);
|
sysTenantPackService.deleteTenantPack(ids);
|
||||||
return Result.ok("删除租户产品包成功");
|
return Result.ok("删除租户产品包成功");
|
||||||
@ -385,7 +386,7 @@ public class SysTenantController {
|
|||||||
public Result<Map<String,Object>> getCurrentUserTenant() {
|
public Result<Map<String,Object>> getCurrentUserTenant() {
|
||||||
Result<Map<String,Object>> result = new Result<Map<String,Object>>();
|
Result<Map<String,Object>> result = new Result<Map<String,Object>>();
|
||||||
try {
|
try {
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
// 代码逻辑说明: [QQYUN-3371]租户逻辑改造,改成关系表------------
|
// 代码逻辑说明: [QQYUN-3371]租户逻辑改造,改成关系表------------
|
||||||
List<Integer> tenantIdList = relationService.getTenantIdsByUserId(sysUser.getId());
|
List<Integer> tenantIdList = relationService.getTenantIdsByUserId(sysUser.getId());
|
||||||
Map<String,Object> map = new HashMap(5);
|
Map<String,Object> map = new HashMap(5);
|
||||||
@ -410,7 +411,7 @@ public class SysTenantController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PutMapping("/invitationUserJoin")
|
@PutMapping("/invitationUserJoin")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tenant:invitation:user')")
|
@RequiresPermissions("system:tenant:invitation:user")
|
||||||
public Result<String> invitationUserJoin(@RequestParam("ids") String ids,@RequestParam(value = "phone", required = false) String phone, @RequestParam(value = "username", required = false) String username){
|
public Result<String> invitationUserJoin(@RequestParam("ids") String ids,@RequestParam(value = "phone", required = false) String phone, @RequestParam(value = "username", required = false) String username){
|
||||||
if(oConvertUtils.isEmpty(phone) && oConvertUtils.isEmpty(username)){
|
if(oConvertUtils.isEmpty(phone) && oConvertUtils.isEmpty(username)){
|
||||||
return Result.error("手机号和用户账号不能同时为空!");
|
return Result.error("手机号和用户账号不能同时为空!");
|
||||||
@ -428,7 +429,7 @@ public class SysTenantController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@RequestMapping(value = "/getTenantUserList", method = RequestMethod.GET)
|
@RequestMapping(value = "/getTenantUserList", method = RequestMethod.GET)
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tenant:user:list')")
|
@RequiresPermissions("system:tenant:user:list")
|
||||||
public Result<IPage<SysUser>> getTenantUserList(SysUser user,
|
public Result<IPage<SysUser>> getTenantUserList(SysUser user,
|
||||||
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
|
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
|
||||||
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
|
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
|
||||||
@ -449,12 +450,12 @@ public class SysTenantController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PutMapping("/leaveTenant")
|
@PutMapping("/leaveTenant")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tenant:leave')")
|
@RequiresPermissions("system:tenant:leave")
|
||||||
public Result<String> leaveTenant(@RequestParam("userIds") String userIds,
|
public Result<String> leaveTenant(@RequestParam("userIds") String userIds,
|
||||||
@RequestParam("tenantId") String tenantId){
|
@RequestParam("tenantId") String tenantId){
|
||||||
Result<String> result = new Result<>();
|
Result<String> result = new Result<>();
|
||||||
//是否开启系统管理模块的多租户数据隔离【SAAS多租户模式】
|
//是否开启系统管理模块的多租户数据隔离【SAAS多租户模式】
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL && !"admin".equals(sysUser.getUsername())){
|
if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL && !"admin".equals(sysUser.getUsername())){
|
||||||
Integer loginSessionTenant = oConvertUtils.getInt(TenantContext.getTenant());
|
Integer loginSessionTenant = oConvertUtils.getInt(TenantContext.getTenant());
|
||||||
if(loginSessionTenant!=null && !loginSessionTenant.equals(Integer.valueOf(tenantId))){
|
if(loginSessionTenant!=null && !loginSessionTenant.equals(Integer.valueOf(tenantId))){
|
||||||
@ -500,7 +501,7 @@ public class SysTenantController {
|
|||||||
@PostMapping("/saveTenantJoinUser")
|
@PostMapping("/saveTenantJoinUser")
|
||||||
public Result<Integer> saveTenantJoinUser(@RequestBody SysTenant sysTenant){
|
public Result<Integer> saveTenantJoinUser(@RequestBody SysTenant sysTenant){
|
||||||
Result<Integer> result = new Result<>();
|
Result<Integer> result = new Result<>();
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
Integer tenantId = sysTenantService.saveTenantJoinUser(sysTenant, sysUser.getId());
|
Integer tenantId = sysTenantService.saveTenantJoinUser(sysTenant, sysUser.getId());
|
||||||
result.setSuccess(true);
|
result.setSuccess(true);
|
||||||
result.setMessage("创建成功");
|
result.setMessage("创建成功");
|
||||||
@ -508,26 +509,26 @@ public class SysTenantController {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* 加入租户通过门牌号【低代码应用专用接口】
|
// * 加入租户通过门牌号【低代码应用专用接口】
|
||||||
* @param sysTenant
|
// * @param sysTenant
|
||||||
*/
|
// */
|
||||||
@PostMapping("/joinTenantByHouseNumber")
|
// @PostMapping("/joinTenantByHouseNumber")
|
||||||
public Result<Integer> joinTenantByHouseNumber(@RequestBody SysTenant sysTenant){
|
// public Result<Integer> joinTenantByHouseNumber(@RequestBody SysTenant sysTenant){
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
// LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
Integer tenantId = sysTenantService.joinTenantByHouseNumber(sysTenant, sysUser.getId());
|
// Integer tenantId = sysTenantService.joinTenantByHouseNumber(sysTenant, sysUser.getId());
|
||||||
Result<Integer> result = new Result<>();
|
// Result<Integer> result = new Result<>();
|
||||||
if(tenantId != 0){
|
// if(tenantId != 0){
|
||||||
result.setMessage("申请加入组织成功");
|
// result.setMessage("申请加入组织成功");
|
||||||
result.setSuccess(true);
|
// result.setSuccess(true);
|
||||||
result.setResult(tenantId);
|
// result.setResult(tenantId);
|
||||||
return result;
|
// return result;
|
||||||
}else{
|
// }else{
|
||||||
result.setMessage("该门牌号不存在");
|
// result.setMessage("该门牌号不存在");
|
||||||
result.setSuccess(false);
|
// result.setSuccess(false);
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页获取租户用户数据(vue3用户租户页面)【低代码应用专用接口】
|
* 分页获取租户用户数据(vue3用户租户页面)【低代码应用专用接口】
|
||||||
@ -548,7 +549,7 @@ public class SysTenantController {
|
|||||||
SysUser user,
|
SysUser user,
|
||||||
HttpServletRequest req) {
|
HttpServletRequest req) {
|
||||||
Page<SysUserTenantVo> page = new Page<SysUserTenantVo>(pageNo, pageSize);
|
Page<SysUserTenantVo> page = new Page<SysUserTenantVo>(pageNo, pageSize);
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
String tenantId = oConvertUtils.getString(TenantContext.getTenant(), "0");
|
String tenantId = oConvertUtils.getString(TenantContext.getTenant(), "0");
|
||||||
IPage<SysUserTenantVo> list = relationService.getUserTenantPageList(page, Arrays.asList(userTenantStatus.split(SymbolConstant.COMMA)), user, Integer.valueOf(tenantId));
|
IPage<SysUserTenantVo> list = relationService.getUserTenantPageList(page, Arrays.asList(userTenantStatus.split(SymbolConstant.COMMA)), user, Integer.valueOf(tenantId));
|
||||||
return Result.ok(list);
|
return Result.ok(list);
|
||||||
@ -563,7 +564,7 @@ public class SysTenantController {
|
|||||||
@GetMapping("/getTenantListByUserId")
|
@GetMapping("/getTenantListByUserId")
|
||||||
//@RequiresPermissions("system:tenant:getTenantListByUserId")
|
//@RequiresPermissions("system:tenant:getTenantListByUserId")
|
||||||
public Result<List<SysUserTenantVo>> getTenantListByUserId(@RequestParam(name = "userTenantStatus", required = false) String userTenantStatus) {
|
public Result<List<SysUserTenantVo>> getTenantListByUserId(@RequestParam(name = "userTenantStatus", required = false) String userTenantStatus) {
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
List<String> list = null;
|
List<String> list = null;
|
||||||
if (oConvertUtils.isNotEmpty(userTenantStatus)) {
|
if (oConvertUtils.isNotEmpty(userTenantStatus)) {
|
||||||
list = Arrays.asList(userTenantStatus.split(SymbolConstant.COMMA));
|
list = Arrays.asList(userTenantStatus.split(SymbolConstant.COMMA));
|
||||||
@ -596,7 +597,7 @@ public class SysTenantController {
|
|||||||
@PutMapping("/cancelTenant")
|
@PutMapping("/cancelTenant")
|
||||||
//@RequiresPermissions("system:tenant:cancelTenant")
|
//@RequiresPermissions("system:tenant:cancelTenant")
|
||||||
public Result<String> cancelTenant(@RequestBody SysTenant sysTenant,HttpServletRequest request) {
|
public Result<String> cancelTenant(@RequestBody SysTenant sysTenant,HttpServletRequest request) {
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
SysTenant tenant = sysTenantService.getById(sysTenant.getId());
|
SysTenant tenant = sysTenantService.getById(sysTenant.getId());
|
||||||
if (null == tenant) {
|
if (null == tenant) {
|
||||||
return Result.error("未找到当前租户信息");
|
return Result.error("未找到当前租户信息");
|
||||||
@ -638,7 +639,7 @@ public class SysTenantController {
|
|||||||
*/
|
*/
|
||||||
@PutMapping("/cancelApplyTenant")
|
@PutMapping("/cancelApplyTenant")
|
||||||
public Result<String> cancelApplyTenant(@RequestParam("tenantId") String tenantId){
|
public Result<String> cancelApplyTenant(@RequestParam("tenantId") String tenantId){
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
sysTenantService.leaveTenant(sysUser.getId(),tenantId);
|
sysTenantService.leaveTenant(sysUser.getId(),tenantId);
|
||||||
return Result.ok("取消申请成功");
|
return Result.ok("取消申请成功");
|
||||||
}
|
}
|
||||||
@ -651,7 +652,7 @@ public class SysTenantController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@DeleteMapping("/deleteLogicDeleted")
|
@DeleteMapping("/deleteLogicDeleted")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tenant:deleteTenantLogic')")
|
@RequiresPermissions("system:tenant:deleteTenantLogic")
|
||||||
public Result<String> deleteTenantLogic(@RequestParam("ids") String ids){
|
public Result<String> deleteTenantLogic(@RequestParam("ids") String ids){
|
||||||
sysTenantService.deleteTenantLogic(ids);
|
sysTenantService.deleteTenantLogic(ids);
|
||||||
return Result.ok("彻底删除成功");
|
return Result.ok("彻底删除成功");
|
||||||
@ -663,7 +664,7 @@ public class SysTenantController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PutMapping("/revertTenantLogic")
|
@PutMapping("/revertTenantLogic")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:tenant:revertTenantLogic')")
|
@RequiresPermissions("system:tenant:revertTenantLogic")
|
||||||
public Result<String> revertTenantLogic(@RequestParam("ids") String ids){
|
public Result<String> revertTenantLogic(@RequestParam("ids") String ids){
|
||||||
sysTenantService.revertTenantLogic(ids);
|
sysTenantService.revertTenantLogic(ids);
|
||||||
return Result.ok("还原成功");
|
return Result.ok("还原成功");
|
||||||
@ -677,7 +678,7 @@ public class SysTenantController {
|
|||||||
*/
|
*/
|
||||||
@DeleteMapping("/exitUserTenant")
|
@DeleteMapping("/exitUserTenant")
|
||||||
public Result<String> exitUserTenant(@RequestBody SysTenant sysTenant,HttpServletRequest request){
|
public Result<String> exitUserTenant(@RequestBody SysTenant sysTenant,HttpServletRequest request){
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
//验证用户是否已存在
|
//验证用户是否已存在
|
||||||
Integer count = relationService.userTenantIzExist(sysUser.getId(),sysTenant.getId());
|
Integer count = relationService.userTenantIzExist(sysUser.getId(),sysTenant.getId());
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
@ -714,6 +715,7 @@ public class SysTenantController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PostMapping("/invitationUser")
|
@PostMapping("/invitationUser")
|
||||||
|
@RequiresPermissions("system:tenant:invitation:user")
|
||||||
public Result<String> invitationUser(@RequestParam(name="phone") String phone,
|
public Result<String> invitationUser(@RequestParam(name="phone") String phone,
|
||||||
@RequestParam(name="departId",defaultValue = "") String departId){
|
@RequestParam(name="departId",defaultValue = "") String departId){
|
||||||
return sysTenantService.invitationUser(phone,departId);
|
return sysTenantService.invitationUser(phone,departId);
|
||||||
@ -901,7 +903,7 @@ public class SysTenantController {
|
|||||||
public Result<IPage<SysTenant>> getTenantPageListByUserId(SysUserTenantVo sysUserTenantVo,
|
public Result<IPage<SysTenant>> getTenantPageListByUserId(SysUserTenantVo sysUserTenantVo,
|
||||||
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
|
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
|
||||||
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize) {
|
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize) {
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
List<String> list = null;
|
List<String> list = null;
|
||||||
String userTenantStatus = sysUserTenantVo.getUserTenantStatus();
|
String userTenantStatus = sysUserTenantVo.getUserTenantStatus();
|
||||||
if (oConvertUtils.isNotEmpty(userTenantStatus)) {
|
if (oConvertUtils.isNotEmpty(userTenantStatus)) {
|
||||||
@ -912,43 +914,43 @@ public class SysTenantController {
|
|||||||
return Result.ok(pageList);
|
return Result.ok(pageList);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* 同意或拒绝加入租户
|
// * 同意或拒绝加入租户
|
||||||
*/
|
// */
|
||||||
@PutMapping("/agreeOrRefuseJoinTenant")
|
// @PutMapping("/agreeOrRefuseJoinTenant")
|
||||||
public Result<String> agreeOrRefuseJoinTenant(@RequestParam("tenantId") Integer tenantId,
|
// public Result<String> agreeOrRefuseJoinTenant(@RequestParam("tenantId") Integer tenantId,
|
||||||
@RequestParam("status") String status){
|
// @RequestParam("status") String status){
|
||||||
//是否开启系统管理模块的多租户数据隔离【SAAS多租户模式】
|
// //是否开启系统管理模块的多租户数据隔离【SAAS多租户模式】
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
// LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
String userId = sysUser.getId();
|
// String userId = sysUser.getId();
|
||||||
SysTenant tenant = sysTenantService.getById(tenantId);
|
// SysTenant tenant = sysTenantService.getById(tenantId);
|
||||||
if(null == tenant){
|
// if(null == tenant){
|
||||||
return Result.error("不存在该组织");
|
// return Result.error("不存在该组织");
|
||||||
}
|
// }
|
||||||
SysUserTenant sysUserTenant = relationService.getUserTenantByTenantId(userId, tenantId);
|
// SysUserTenant sysUserTenant = relationService.getUserTenantByTenantId(userId, tenantId);
|
||||||
if (null == sysUserTenant) {
|
// if (null == sysUserTenant) {
|
||||||
return Result.error("该用户不存在该组织中,无权修改");
|
// return Result.error("该用户不存在该组织中,无权修改");
|
||||||
}
|
// }
|
||||||
String content = "";
|
// String content = "";
|
||||||
SysUser user = new SysUser();
|
// SysUser user = new SysUser();
|
||||||
user.setUsername(sysUserTenant.getCreateBy());
|
// user.setUsername(sysUserTenant.getCreateBy());
|
||||||
String realname = oConvertUtils.getString(sysUser.getRealname(),sysUser.getUsername());
|
// String realname = oConvertUtils.getString(sysUser.getRealname(),sysUser.getUsername());
|
||||||
//成功加入
|
// //成功加入
|
||||||
if(CommonConstant.USER_TENANT_NORMAL.equals(status)){
|
// if(CommonConstant.USER_TENANT_NORMAL.equals(status)){
|
||||||
//修改租户状态
|
// //修改租户状态
|
||||||
relationService.agreeJoinTenant(userId,tenantId);
|
// relationService.agreeJoinTenant(userId,tenantId);
|
||||||
content = content + realname + "已同意您发送的加入 " + tenant.getName() + " 的邀请";
|
// content = content + realname + "已同意您发送的加入 " + tenant.getName() + " 的邀请";
|
||||||
sysTenantService.sendMsgForAgreeAndRefuseJoin(user, content);
|
// sysTenantService.sendMsgForAgreeAndRefuseJoin(user, content);
|
||||||
return Result.OK("您已同意该组织的邀请");
|
// return Result.OK("您已同意该组织的邀请");
|
||||||
}else if(CommonConstant.USER_TENANT_REFUSE.equals(status)){
|
// }else if(CommonConstant.USER_TENANT_REFUSE.equals(status)){
|
||||||
//直接删除关系表即可
|
// //直接删除关系表即可
|
||||||
relationService.refuseJoinTenant(userId,tenantId);
|
// relationService.refuseJoinTenant(userId,tenantId);
|
||||||
content = content + realname + "拒绝了您发送的加入 " + tenant.getName() + " 的邀请";
|
// content = content + realname + "拒绝了您发送的加入 " + tenant.getName() + " 的邀请";
|
||||||
sysTenantService.sendMsgForAgreeAndRefuseJoin(user, content);
|
// sysTenantService.sendMsgForAgreeAndRefuseJoin(user, content);
|
||||||
return Result.OK("您已成功拒绝该组织的邀请");
|
// return Result.OK("您已成功拒绝该组织的邀请");
|
||||||
}
|
// }
|
||||||
return Result.error("类型不匹配,禁止修改数据");
|
// return Result.error("类型不匹配,禁止修改数据");
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 目前只给敲敲云租户下删除用户使用
|
* 目前只给敲敲云租户下删除用户使用
|
||||||
|
|||||||
@ -11,8 +11,12 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
|||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.aspect.annotation.PermissionData;
|
import org.jeecg.common.aspect.annotation.PermissionData;
|
||||||
|
import org.jeecg.common.base.BaseMap;
|
||||||
import org.jeecg.common.config.TenantContext;
|
import org.jeecg.common.config.TenantContext;
|
||||||
import org.jeecg.common.constant.CacheConstant;
|
import org.jeecg.common.constant.CacheConstant;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
@ -25,9 +29,7 @@ import org.jeecg.common.system.vo.LoginUser;
|
|||||||
import org.jeecg.common.util.*;
|
import org.jeecg.common.util.*;
|
||||||
import org.jeecg.config.JeecgBaseConfig;
|
import org.jeecg.config.JeecgBaseConfig;
|
||||||
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecg.modules.base.service.BaseCommonService;
|
import org.jeecg.modules.base.service.BaseCommonService;
|
||||||
import org.jeecg.modules.jmreport.common.annotation.RequiresRoles;
|
|
||||||
import org.jeecg.modules.system.entity.*;
|
import org.jeecg.modules.system.entity.*;
|
||||||
import org.jeecg.modules.system.excelstyle.ExcelExportSysUserStyle;
|
import org.jeecg.modules.system.excelstyle.ExcelExportSysUserStyle;
|
||||||
import org.jeecg.modules.system.model.DepartIdModel;
|
import org.jeecg.modules.system.model.DepartIdModel;
|
||||||
@ -46,7 +48,6 @@ import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
|
|||||||
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
|
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
@ -146,7 +147,7 @@ public class SysUserController {
|
|||||||
* @param req
|
* @param req
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:listAll')")
|
@RequiresPermissions("system:user:listAll")
|
||||||
@RequestMapping(value = "/listAll", method = RequestMethod.GET)
|
@RequestMapping(value = "/listAll", method = RequestMethod.GET)
|
||||||
public Result<IPage<SysUser>> queryAllPageList(SysUser user, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
|
public Result<IPage<SysUser>> queryAllPageList(SysUser user, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
|
||||||
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, HttpServletRequest req) {
|
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, HttpServletRequest req) {
|
||||||
@ -154,7 +155,7 @@ public class SysUserController {
|
|||||||
return sysUserService.queryPageList(req, queryWrapper, pageSize, pageNo);
|
return sysUserService.queryPageList(req, queryWrapper, pageSize, pageNo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:add')")
|
@RequiresPermissions("system:user:add")
|
||||||
@RequestMapping(value = "/add", method = RequestMethod.POST)
|
@RequestMapping(value = "/add", method = RequestMethod.POST)
|
||||||
public Result<SysUser> add(@RequestBody JSONObject jsonObject) {
|
public Result<SysUser> add(@RequestBody JSONObject jsonObject) {
|
||||||
Result<SysUser> result = new Result<SysUser>();
|
Result<SysUser> result = new Result<SysUser>();
|
||||||
@ -185,7 +186,7 @@ public class SysUserController {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:edit')")
|
@RequiresPermissions("system:user:edit")
|
||||||
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
|
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
|
||||||
public Result<SysUser> edit(@RequestBody JSONObject jsonObject) {
|
public Result<SysUser> edit(@RequestBody JSONObject jsonObject) {
|
||||||
Result<SysUser> result = new Result<SysUser>();
|
Result<SysUser> result = new Result<SysUser>();
|
||||||
@ -230,7 +231,7 @@ public class SysUserController {
|
|||||||
* @param jsonObject
|
* @param jsonObject
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:addTenantUser')")
|
@RequiresPermissions("system:user:addTenantUser")
|
||||||
@RequestMapping(value = "/addTenantUser", method = RequestMethod.POST)
|
@RequestMapping(value = "/addTenantUser", method = RequestMethod.POST)
|
||||||
public Result<SysUser> addTenantUser(@RequestBody JSONObject jsonObject) {
|
public Result<SysUser> addTenantUser(@RequestBody JSONObject jsonObject) {
|
||||||
Result<SysUser> result = new Result<SysUser>();
|
Result<SysUser> result = new Result<SysUser>();
|
||||||
@ -263,7 +264,7 @@ public class SysUserController {
|
|||||||
/**
|
/**
|
||||||
* 删除用户
|
* 删除用户
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:delete')")
|
@RequiresPermissions("system:user:delete")
|
||||||
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
|
||||||
public Result<?> delete(@RequestParam(name="id",required=true) String id) {
|
public Result<?> delete(@RequestParam(name="id",required=true) String id) {
|
||||||
baseCommonService.addLog("删除用户,id: " +id ,CommonConstant.LOG_TYPE_2, 3);
|
baseCommonService.addLog("删除用户,id: " +id ,CommonConstant.LOG_TYPE_2, 3);
|
||||||
@ -279,7 +280,7 @@ public class SysUserController {
|
|||||||
/**
|
/**
|
||||||
* 批量删除用户
|
* 批量删除用户
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:deleteBatch')")
|
@RequiresPermissions("system:user:deleteBatch")
|
||||||
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
|
||||||
public Result<?> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
|
public Result<?> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
|
||||||
baseCommonService.addLog("批量删除用户, ids: " +ids ,CommonConstant.LOG_TYPE_2, 3);
|
baseCommonService.addLog("批量删除用户, ids: " +ids ,CommonConstant.LOG_TYPE_2, 3);
|
||||||
@ -298,7 +299,7 @@ public class SysUserController {
|
|||||||
* @param jsonObject
|
* @param jsonObject
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:frozenBatch')")
|
@RequiresPermissions("system:user:frozenBatch")
|
||||||
@RequestMapping(value = "/frozenBatch", method = RequestMethod.PUT)
|
@RequestMapping(value = "/frozenBatch", method = RequestMethod.PUT)
|
||||||
public Result<SysUser> frozenBatch(@RequestBody JSONObject jsonObject) {
|
public Result<SysUser> frozenBatch(@RequestBody JSONObject jsonObject) {
|
||||||
Result<SysUser> result = new Result<SysUser>();
|
Result<SysUser> result = new Result<SysUser>();
|
||||||
@ -327,7 +328,7 @@ public class SysUserController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@RequiresRoles({"admin"})
|
@RequiresRoles({"admin"})
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:resetPassword')")
|
@RequiresPermissions("system:user:resetPassword")
|
||||||
@RequestMapping(value = "/resetPassword", method = RequestMethod.PUT)
|
@RequestMapping(value = "/resetPassword", method = RequestMethod.PUT)
|
||||||
public Result<SysUser> resetPassword(@RequestParam(name = "usernames") String usernames) {
|
public Result<SysUser> resetPassword(@RequestParam(name = "usernames") String usernames) {
|
||||||
Result<SysUser> result = new Result<SysUser>();
|
Result<SysUser> result = new Result<SysUser>();
|
||||||
@ -342,7 +343,7 @@ public class SysUserController {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:queryById')")
|
@RequiresPermissions("system:user:queryById")
|
||||||
@RequestMapping(value = "/queryById", method = RequestMethod.GET)
|
@RequestMapping(value = "/queryById", method = RequestMethod.GET)
|
||||||
public Result<SysUser> queryById(@RequestParam(name = "id", required = true) String id) {
|
public Result<SysUser> queryById(@RequestParam(name = "id", required = true) String id) {
|
||||||
Result<SysUser> result = new Result<SysUser>();
|
Result<SysUser> result = new Result<SysUser>();
|
||||||
@ -356,7 +357,7 @@ public class SysUserController {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:queryUserRole')")
|
@RequiresPermissions("system:user:queryUserRole")
|
||||||
@RequestMapping(value = "/queryUserRole", method = RequestMethod.GET)
|
@RequestMapping(value = "/queryUserRole", method = RequestMethod.GET)
|
||||||
public Result<List<String>> queryUserRole(@RequestParam(name = "userid", required = true) String userid) {
|
public Result<List<String>> queryUserRole(@RequestParam(name = "userid", required = true) String userid) {
|
||||||
Result<List<String>> result = new Result<>();
|
Result<List<String>> result = new Result<>();
|
||||||
@ -409,7 +410,7 @@ public class SysUserController {
|
|||||||
/**
|
/**
|
||||||
* 修改密码
|
* 修改密码
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:changepwd')")
|
@RequiresPermissions("system:user:changepwd")
|
||||||
@RequestMapping(value = "/changePassword", method = RequestMethod.PUT)
|
@RequestMapping(value = "/changePassword", method = RequestMethod.PUT)
|
||||||
public Result<?> changePassword(@RequestBody SysUser sysUser, HttpServletRequest request) {
|
public Result<?> changePassword(@RequestBody SysUser sysUser, HttpServletRequest request) {
|
||||||
//-------------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------------
|
||||||
@ -426,7 +427,7 @@ public class SysUserController {
|
|||||||
}
|
}
|
||||||
sysUser.setId(u.getId());
|
sysUser.setId(u.getId());
|
||||||
// 代码逻辑说明: [VUEN-234]修改密码添加敏感日志------------
|
// 代码逻辑说明: [VUEN-234]修改密码添加敏感日志------------
|
||||||
LoginUser loginUser = SecureUtil.currentUser();
|
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
baseCommonService.addLog("修改用户 "+sysUser.getUsername()+" 的密码,操作人: " +loginUser.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
|
baseCommonService.addLog("修改用户 "+sysUser.getUsername()+" 的密码,操作人: " +loginUser.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
|
||||||
return sysUserService.changePassword(sysUser);
|
return sysUserService.changePassword(sysUser);
|
||||||
}
|
}
|
||||||
@ -539,7 +540,7 @@ public class SysUserController {
|
|||||||
* @param request
|
* @param request
|
||||||
* @param sysUser
|
* @param sysUser
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:export')")
|
@RequiresPermissions("system:user:export")
|
||||||
@RequestMapping(value = "/exportXls")
|
@RequestMapping(value = "/exportXls")
|
||||||
public ModelAndView exportXls(SysUser sysUser,HttpServletRequest request) {
|
public ModelAndView exportXls(SysUser sysUser,HttpServletRequest request) {
|
||||||
// Step.1 组装查询条件
|
// Step.1 组装查询条件
|
||||||
@ -575,7 +576,7 @@ public class SysUserController {
|
|||||||
//导出文件名称
|
//导出文件名称
|
||||||
mv.addObject(NormalExcelConstants.FILE_NAME, "用户列表");
|
mv.addObject(NormalExcelConstants.FILE_NAME, "用户列表");
|
||||||
mv.addObject(NormalExcelConstants.CLASS, SysUserExportVo.class);
|
mv.addObject(NormalExcelConstants.CLASS, SysUserExportVo.class);
|
||||||
LoginUser user = SecureUtil.currentUser();
|
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
ExportParams exportParams = new ExportParams("导入规则:\n" +
|
ExportParams exportParams = new ExportParams("导入规则:\n" +
|
||||||
"1. 用户名为必填项,仅支持新增数据导入;\n" +
|
"1. 用户名为必填项,仅支持新增数据导入;\n" +
|
||||||
"2. 多个部门、角色或负责部门请用英文分号 ; 分隔,如:财务部;研发部;\n" +
|
"2. 多个部门、角色或负责部门请用英文分号 ; 分隔,如:财务部;研发部;\n" +
|
||||||
@ -606,7 +607,7 @@ public class SysUserController {
|
|||||||
* @param response
|
* @param response
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:import')")
|
@RequiresPermissions("system:user:import")
|
||||||
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
|
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
|
||||||
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response)throws IOException {
|
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response)throws IOException {
|
||||||
//return ImportOldUserUtil.importOldSysUser(request);
|
//return ImportOldUserUtil.importOldSysUser(request);
|
||||||
@ -661,14 +662,14 @@ public class SysUserController {
|
|||||||
/**
|
/**
|
||||||
* 首页用户重置密码
|
* 首页用户重置密码
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:updatepwd')")
|
@RequiresPermissions("system:user:updatepwd")
|
||||||
@RequestMapping(value = "/updatePassword", method = RequestMethod.PUT)
|
@RequestMapping(value = "/updatePassword", method = RequestMethod.PUT)
|
||||||
public Result<?> updatePassword(@RequestBody JSONObject json) {
|
public Result<?> updatePassword(@RequestBody JSONObject json) {
|
||||||
String username = json.getString("username");
|
String username = json.getString("username");
|
||||||
String oldpassword = json.getString("oldpassword");
|
String oldpassword = json.getString("oldpassword");
|
||||||
String password = json.getString("password");
|
String password = json.getString("password");
|
||||||
String confirmpassword = json.getString("confirmpassword");
|
String confirmpassword = json.getString("confirmpassword");
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
|
||||||
if(!sysUser.getUsername().equals(username)){
|
if(!sysUser.getUsername().equals(username)){
|
||||||
return Result.error("只允许修改自己的密码!");
|
return Result.error("只允许修改自己的密码!");
|
||||||
}
|
}
|
||||||
@ -677,7 +678,7 @@ public class SysUserController {
|
|||||||
return Result.error("用户不存在!");
|
return Result.error("用户不存在!");
|
||||||
}
|
}
|
||||||
// 代码逻辑说明: [VUEN-234]修改密码添加敏感日志------------
|
// 代码逻辑说明: [VUEN-234]修改密码添加敏感日志------------
|
||||||
LoginUser loginUser = SecureUtil.currentUser();
|
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
baseCommonService.addLog("修改密码,username: " +loginUser.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
|
baseCommonService.addLog("修改密码,username: " +loginUser.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
|
||||||
return sysUserService.resetPassword(username,oldpassword,password,confirmpassword);
|
return sysUserService.resetPassword(username,oldpassword,password,confirmpassword);
|
||||||
}
|
}
|
||||||
@ -702,7 +703,7 @@ public class SysUserController {
|
|||||||
* @param
|
* @param
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:addUserRole')")
|
@RequiresPermissions("system:user:addUserRole")
|
||||||
@RequestMapping(value = "/addSysUserRole", method = RequestMethod.POST)
|
@RequestMapping(value = "/addSysUserRole", method = RequestMethod.POST)
|
||||||
public Result<String> addSysUserRole(@RequestBody SysUserRoleVO sysUserRoleVO) {
|
public Result<String> addSysUserRole(@RequestBody SysUserRoleVO sysUserRoleVO) {
|
||||||
Result<String> result = new Result<String>();
|
Result<String> result = new Result<String>();
|
||||||
@ -734,7 +735,7 @@ public class SysUserController {
|
|||||||
* @param
|
* @param
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:deleteRole')")
|
@RequiresPermissions("system:user:deleteRole")
|
||||||
@RequestMapping(value = "/deleteUserRole", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/deleteUserRole", method = RequestMethod.DELETE)
|
||||||
public Result<SysUserRole> deleteUserRole(@RequestParam(name="roleId") String roleId,
|
public Result<SysUserRole> deleteUserRole(@RequestParam(name="roleId") String roleId,
|
||||||
@RequestParam(name="userId",required=true) String userId
|
@RequestParam(name="userId",required=true) String userId
|
||||||
@ -758,7 +759,7 @@ public class SysUserController {
|
|||||||
* @param
|
* @param
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:deleteRoleBatch')")
|
@RequiresPermissions("system:user:deleteRoleBatch")
|
||||||
@RequestMapping(value = "/deleteUserRoleBatch", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/deleteUserRoleBatch", method = RequestMethod.DELETE)
|
||||||
public Result<SysUserRole> deleteUserRoleBatch(
|
public Result<SysUserRole> deleteUserRoleBatch(
|
||||||
@RequestParam(name="roleId") String roleId,
|
@RequestParam(name="roleId") String roleId,
|
||||||
@ -790,7 +791,7 @@ public class SysUserController {
|
|||||||
List<String> subDepids = new ArrayList<>();
|
List<String> subDepids = new ArrayList<>();
|
||||||
//部门id为空时,查询我的部门下所有用户
|
//部门id为空时,查询我的部门下所有用户
|
||||||
if(oConvertUtils.isEmpty(depId)){
|
if(oConvertUtils.isEmpty(depId)){
|
||||||
LoginUser user = SecureUtil.currentUser();
|
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
int userIdentity = user.getUserIdentity() != null?user.getUserIdentity():CommonConstant.USER_IDENTITY_1;
|
int userIdentity = user.getUserIdentity() != null?user.getUserIdentity():CommonConstant.USER_IDENTITY_1;
|
||||||
// 代码逻辑说明: [QQYUN-10775]验证码可以复用 #7674------------
|
// 代码逻辑说明: [QQYUN-10775]验证码可以复用 #7674------------
|
||||||
if(oConvertUtils.isNotEmpty(userIdentity) && userIdentity == CommonConstant.USER_IDENTITY_2
|
if(oConvertUtils.isNotEmpty(userIdentity) && userIdentity == CommonConstant.USER_IDENTITY_2
|
||||||
@ -938,7 +939,7 @@ public class SysUserController {
|
|||||||
/**
|
/**
|
||||||
* 给指定部门添加对应的用户
|
* 给指定部门添加对应的用户
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:editDepartWithUser')")
|
@RequiresPermissions("system:user:editDepartWithUser")
|
||||||
@RequestMapping(value = "/editSysDepartWithUser", method = RequestMethod.POST)
|
@RequestMapping(value = "/editSysDepartWithUser", method = RequestMethod.POST)
|
||||||
public Result<String> editSysDepartWithUser(@RequestBody SysDepartUsersVO sysDepartUsersVO) {
|
public Result<String> editSysDepartWithUser(@RequestBody SysDepartUsersVO sysDepartUsersVO) {
|
||||||
Result<String> result = new Result<String>();
|
Result<String> result = new Result<String>();
|
||||||
@ -973,7 +974,7 @@ public class SysUserController {
|
|||||||
/**
|
/**
|
||||||
* 删除指定机构的用户关系
|
* 删除指定机构的用户关系
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:deleteUserInDepart')")
|
@RequiresPermissions("system:user:deleteUserInDepart")
|
||||||
@RequestMapping(value = "/deleteUserInDepart", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/deleteUserInDepart", method = RequestMethod.DELETE)
|
||||||
public Result<SysUserDepart> deleteUserInDepart(@RequestParam(name="depId") String depId,
|
public Result<SysUserDepart> deleteUserInDepart(@RequestParam(name="depId") String depId,
|
||||||
@RequestParam(name="userId",required=true) String userId
|
@RequestParam(name="userId",required=true) String userId
|
||||||
@ -1005,7 +1006,7 @@ public class SysUserController {
|
|||||||
/**
|
/**
|
||||||
* 批量删除指定机构的用户关系
|
* 批量删除指定机构的用户关系
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:deleteUserInDepartBatch')")
|
@RequiresPermissions("system:user:deleteUserInDepartBatch")
|
||||||
@RequestMapping(value = "/deleteUserInDepartBatch", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/deleteUserInDepartBatch", method = RequestMethod.DELETE)
|
||||||
public Result<SysUserDepart> deleteUserInDepartBatch(
|
public Result<SysUserDepart> deleteUserInDepartBatch(
|
||||||
@RequestParam(name="depId") String depId,
|
@RequestParam(name="depId") String depId,
|
||||||
@ -1037,7 +1038,7 @@ public class SysUserController {
|
|||||||
public Result<Map<String,Object>> getCurrentUserDeparts() {
|
public Result<Map<String,Object>> getCurrentUserDeparts() {
|
||||||
Result<Map<String,Object>> result = new Result<Map<String,Object>>();
|
Result<Map<String,Object>> result = new Result<Map<String,Object>>();
|
||||||
try {
|
try {
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
|
||||||
List<SysDepart> list = this.sysDepartService.queryUserDeparts(sysUser.getId());
|
List<SysDepart> list = this.sysDepartService.queryUserDeparts(sysUser.getId());
|
||||||
Map<String,Object> map = new HashMap(5);
|
Map<String,Object> map = new HashMap(5);
|
||||||
map.put("list", list);
|
map.put("list", list);
|
||||||
@ -1418,7 +1419,7 @@ public class SysUserController {
|
|||||||
* @param userIds 被删除的用户ID,多个id用半角逗号分割
|
* @param userIds 被删除的用户ID,多个id用半角逗号分割
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:deleteRecycleBin')")
|
@RequiresPermissions("system:user:deleteRecycleBin")
|
||||||
@RequestMapping(value = "/deleteRecycleBin", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/deleteRecycleBin", method = RequestMethod.DELETE)
|
||||||
public Result deleteRecycleBin(@RequestParam("userIds") String userIds) {
|
public Result deleteRecycleBin(@RequestParam("userIds") String userIds) {
|
||||||
if (StringUtils.isNotBlank(userIds)) {
|
if (StringUtils.isNotBlank(userIds)) {
|
||||||
@ -1433,7 +1434,7 @@ public class SysUserController {
|
|||||||
* @param jsonObject
|
* @param jsonObject
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:app:edit')")
|
@RequiresPermissions("system:user:app:edit")
|
||||||
@RequestMapping(value = "/appEdit", method = {RequestMethod.PUT,RequestMethod.POST})
|
@RequestMapping(value = "/appEdit", method = {RequestMethod.PUT,RequestMethod.POST})
|
||||||
public Result<SysUser> appEdit(HttpServletRequest request,@RequestBody JSONObject jsonObject) {
|
public Result<SysUser> appEdit(HttpServletRequest request,@RequestBody JSONObject jsonObject) {
|
||||||
Result<SysUser> result = new Result<SysUser>();
|
Result<SysUser> result = new Result<SysUser>();
|
||||||
@ -1800,7 +1801,7 @@ public class SysUserController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PostMapping("/login/setting/userEdit")
|
@PostMapping("/login/setting/userEdit")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:user:setting:edit')")
|
@RequiresPermissions("system:user:setting:edit")
|
||||||
public Result<String> userEdit(@RequestBody SysUser sysUser, HttpServletRequest request) {
|
public Result<String> userEdit(@RequestBody SysUser sysUser, HttpServletRequest request) {
|
||||||
String username = JwtUtil.getUserNameByToken(request);
|
String username = JwtUtil.getUserNameByToken(request);
|
||||||
SysUser user = sysUserService.getById(sysUser.getId());
|
SysUser user = sysUserService.getById(sysUser.getId());
|
||||||
@ -1912,7 +1913,7 @@ public class SysUserController {
|
|||||||
public Result<?> changeLoginTenantId(@RequestBody SysUser sysUser){
|
public Result<?> changeLoginTenantId(@RequestBody SysUser sysUser){
|
||||||
Result<String> result = new Result<>();
|
Result<String> result = new Result<>();
|
||||||
Integer tenantId = sysUser.getLoginTenantId();
|
Integer tenantId = sysUser.getLoginTenantId();
|
||||||
LoginUser loginUser = SecureUtil.currentUser();
|
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
String userId = loginUser.getId();
|
String userId = loginUser.getId();
|
||||||
|
|
||||||
// 判断 指定的租户ID是不是当前登录用户的租户
|
// 判断 指定的租户ID是不是当前登录用户的租户
|
||||||
@ -2068,7 +2069,7 @@ public class SysUserController {
|
|||||||
return Result.OK("no");
|
return Result.OK("no");
|
||||||
}
|
}
|
||||||
|
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
SysUser user = sysUserService.getById(sysUser.getId());
|
SysUser user = sysUserService.getById(sysUser.getId());
|
||||||
String passwordEncode = PasswordUtil.encrypt(user.getUsername(), PasswordConstant.DEFAULT_PASSWORD, user.getSalt());
|
String passwordEncode = PasswordUtil.encrypt(user.getUsername(), PasswordConstant.DEFAULT_PASSWORD, user.getSalt());
|
||||||
if(passwordEncode.equals(user.getPassword())){
|
if(passwordEncode.equals(user.getPassword())){
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
package org.jeecg.modules.system.controller;
|
package org.jeecg.modules.system.controller;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.constant.CacheConstant;
|
import org.jeecg.common.constant.CacheConstant;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
@ -16,14 +19,9 @@ import org.jeecg.modules.system.service.impl.SysBaseApiImpl;
|
|||||||
import org.jeecg.modules.system.vo.SysUserOnlineVO;
|
import org.jeecg.modules.system.vo.SysUserOnlineVO;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.cache.CacheManager;
|
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -50,11 +48,8 @@ public class SysUserOnlineController {
|
|||||||
private SysBaseApiImpl sysBaseApi;
|
private SysBaseApiImpl sysBaseApi;
|
||||||
@Resource
|
@Resource
|
||||||
private BaseCommonService baseCommonService;
|
private BaseCommonService baseCommonService;
|
||||||
@Autowired
|
|
||||||
private OAuth2AuthorizationService authorizationService;
|
|
||||||
@Autowired
|
|
||||||
private CacheManager cacheManager;
|
|
||||||
|
|
||||||
|
@RequiresPermissions("system:online:list")
|
||||||
@RequestMapping(value = "/list", method = RequestMethod.GET)
|
@RequestMapping(value = "/list", method = RequestMethod.GET)
|
||||||
public Result<Page<SysUserOnlineVO>> list(@RequestParam(name="username", required=false) String username,
|
public Result<Page<SysUserOnlineVO>> list(@RequestParam(name="username", required=false) String username,
|
||||||
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,@RequestParam(name="pageSize", defaultValue="10") Integer pageSize) {
|
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,@RequestParam(name="pageSize", defaultValue="10") Integer pageSize) {
|
||||||
@ -107,6 +102,7 @@ public class SysUserOnlineController {
|
|||||||
/**
|
/**
|
||||||
* 强退用户
|
* 强退用户
|
||||||
*/
|
*/
|
||||||
|
@RequiresPermissions("system:online:forceLogout")
|
||||||
@RequestMapping(value = "/forceLogout",method = RequestMethod.POST)
|
@RequestMapping(value = "/forceLogout",method = RequestMethod.POST)
|
||||||
public Result<Object> forceLogout(@RequestBody SysUserOnlineVO online) {
|
public Result<Object> forceLogout(@RequestBody SysUserOnlineVO online) {
|
||||||
//用户退出逻辑
|
//用户退出逻辑
|
||||||
@ -124,13 +120,8 @@ public class SysUserOnlineController {
|
|||||||
redisUtil.del(CommonConstant.PREFIX_USER_SHIRO_CACHE + sysUser.getId());
|
redisUtil.del(CommonConstant.PREFIX_USER_SHIRO_CACHE + sysUser.getId());
|
||||||
//清空用户的缓存信息(包括部门信息),例如sys:cache:user::<username>
|
//清空用户的缓存信息(包括部门信息),例如sys:cache:user::<username>
|
||||||
redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, sysUser.getUsername()));
|
redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, sysUser.getUsername()));
|
||||||
//调用logout
|
//调用shiro的logout
|
||||||
OAuth2Authorization authorization = authorizationService.findByToken(online.getToken(), OAuth2TokenType.ACCESS_TOKEN);
|
SecurityUtils.getSubject().logout();
|
||||||
|
|
||||||
// 清空用户信息
|
|
||||||
cacheManager.getCache("user_details").evict(authorization.getPrincipalName());
|
|
||||||
// 清空access token
|
|
||||||
authorizationService.remove(authorization);
|
|
||||||
return Result.ok("退出登录成功!");
|
return Result.ok("退出登录成功!");
|
||||||
}else {
|
}else {
|
||||||
return Result.error("Token无效!");
|
return Result.error("Token无效!");
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
package org.jeecg.modules.system.controller;
|
package org.jeecg.modules.system.controller;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.jeecg.dingtalk.api.core.response.Response;
|
import com.jeecg.dingtalk.api.core.response.Response;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
import org.jeecg.common.api.dto.message.MessageDTO;
|
import org.jeecg.common.api.dto.message.MessageDTO;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.config.TenantContext;
|
import org.jeecg.common.config.TenantContext;
|
||||||
@ -17,7 +18,6 @@ import org.jeecg.common.system.vo.LoginUser;
|
|||||||
import org.jeecg.common.util.TokenUtils;
|
import org.jeecg.common.util.TokenUtils;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
|
||||||
import org.jeecg.modules.system.entity.SysThirdAccount;
|
import org.jeecg.modules.system.entity.SysThirdAccount;
|
||||||
import org.jeecg.modules.system.entity.SysThirdAppConfig;
|
import org.jeecg.modules.system.entity.SysThirdAppConfig;
|
||||||
import org.jeecg.modules.system.service.ISysThirdAccountService;
|
import org.jeecg.modules.system.service.ISysThirdAccountService;
|
||||||
@ -28,8 +28,6 @@ import org.jeecg.modules.system.vo.thirdapp.JwSysUserDepartVo;
|
|||||||
import org.jeecg.modules.system.vo.thirdapp.JwUserDepartVo;
|
import org.jeecg.modules.system.vo.thirdapp.JwUserDepartVo;
|
||||||
import org.jeecg.modules.system.vo.thirdapp.SyncInfoVo;
|
import org.jeecg.modules.system.vo.thirdapp.SyncInfoVo;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
@ -426,7 +424,7 @@ public class ThirdAppController {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@DeleteMapping(value = "/deleteThirdAppConfig")
|
@DeleteMapping(value = "/deleteThirdAppConfig")
|
||||||
@PreAuthorize("@jps.requiresPermissions('system:third:config:delete')")
|
@RequiresPermissions("system:third:config:delete")
|
||||||
public Result<String> deleteThirdAppConfig(@RequestParam(name="id",required=true) String id) {
|
public Result<String> deleteThirdAppConfig(@RequestParam(name="id",required=true) String id) {
|
||||||
Result<String> result = new Result<>();
|
Result<String> result = new Result<>();
|
||||||
SysThirdAppConfig config = appConfigService.getById(id);
|
SysThirdAppConfig config = appConfigService.getById(id);
|
||||||
@ -506,7 +504,7 @@ public class ThirdAppController {
|
|||||||
*/
|
*/
|
||||||
@GetMapping("/getThirdAccountByUserId")
|
@GetMapping("/getThirdAccountByUserId")
|
||||||
public Result<List<SysThirdAccount>> getThirdAccountByUserId(@RequestParam(name="thirdType") String thirdType){
|
public Result<List<SysThirdAccount>> getThirdAccountByUserId(@RequestParam(name="thirdType") String thirdType){
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
LambdaQueryWrapper<SysThirdAccount> query = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<SysThirdAccount> query = new LambdaQueryWrapper<>();
|
||||||
//根据id查询
|
//根据id查询
|
||||||
query.eq(SysThirdAccount::getSysUserId,sysUser.getId());
|
query.eq(SysThirdAccount::getSysUserId,sysUser.getId());
|
||||||
@ -537,7 +535,7 @@ public class ThirdAppController {
|
|||||||
*/
|
*/
|
||||||
@DeleteMapping("/deleteThirdAccount")
|
@DeleteMapping("/deleteThirdAccount")
|
||||||
public Result<String> deleteThirdAccountById(@RequestBody SysThirdAccount sysThirdAccount){
|
public Result<String> deleteThirdAccountById(@RequestBody SysThirdAccount sysThirdAccount){
|
||||||
LoginUser sysUser = SecureUtil.currentUser();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
if(!sysUser.getId().equals(sysThirdAccount.getSysUserId())){
|
if(!sysUser.getId().equals(sysThirdAccount.getSysUserId())){
|
||||||
return Result.error("无权修改他人信息");
|
return Result.error("无权修改他人信息");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import me.zhyd.oauth.model.AuthCallback;
|
|||||||
import me.zhyd.oauth.model.AuthResponse;
|
import me.zhyd.oauth.model.AuthResponse;
|
||||||
import me.zhyd.oauth.request.AuthRequest;
|
import me.zhyd.oauth.request.AuthRequest;
|
||||||
import me.zhyd.oauth.utils.AuthStateUtils;
|
import me.zhyd.oauth.utils.AuthStateUtils;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import me.zhyd.oauth.utils.StringUtils;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.constant.enums.MessageTypeEnum;
|
import org.jeecg.common.constant.enums.MessageTypeEnum;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user