diff --git a/pom.xml b/pom.xml
index 9a0498c..7f102f9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -132,6 +132,22 @@
provided
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
org.apache.commons
commons-lang3
diff --git a/src/main/java/com/zsc/edu/dify/framework/security/CustomAccessDeniedHandler.java b/src/main/java/com/zsc/edu/dify/framework/security/CustomAccessDeniedHandler.java
index deafa51..e0ee566 100644
--- a/src/main/java/com/zsc/edu/dify/framework/security/CustomAccessDeniedHandler.java
+++ b/src/main/java/com/zsc/edu/dify/framework/security/CustomAccessDeniedHandler.java
@@ -6,6 +6,7 @@ import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
+import org.springframework.beans.factory.BeanFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authorization.AuthorizationDeniedException;
@@ -38,11 +39,10 @@ public class CustomAccessDeniedHandler implements AccessDeniedHandler {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
result = new ExceptionResult("凭证已过期,请重新登录", HttpStatus.UNAUTHORIZED.value(),
LocalDateTime.now());
- } else if (ex instanceof AuthorizationDeniedException) {
- // 会话已存在,禁止重复登录,返回401
- response.setStatus(HttpStatus.UNAUTHORIZED.value());
- result = new ExceptionResult("当前账号已在其他设备登录,请先退出再尝试登录", HttpStatus.UNAUTHORIZED.value(),
- LocalDateTime.now());
+// } else if (ex instanceof AuthorizationDeniedException) {
+// response.setStatus(HttpStatus.FORBIDDEN.value());
+// result = new ExceptionResult("权限不足", HttpStatus.FORBIDDEN.value(),
+// LocalDateTime.now());
} else {
// 403
response.setStatus(HttpStatus.FORBIDDEN.value());
diff --git a/src/main/java/com/zsc/edu/dify/framework/security/CustomSessionInformationExpiredStrategy.java b/src/main/java/com/zsc/edu/dify/framework/security/CustomSessionInformationExpiredStrategy.java
index 4c59a9e..c909f5b 100644
--- a/src/main/java/com/zsc/edu/dify/framework/security/CustomSessionInformationExpiredStrategy.java
+++ b/src/main/java/com/zsc/edu/dify/framework/security/CustomSessionInformationExpiredStrategy.java
@@ -9,6 +9,7 @@ import org.springframework.stereotype.Component;
import java.io.IOException;
import java.time.LocalDateTime;
+import java.util.Date;
import java.util.Map;
/**
@@ -26,8 +27,9 @@ public class CustomSessionInformationExpiredStrategy implements SessionInformati
response.getWriter().print(objectMapper.writeValueAsString(Map.of(
"msg", "会话已过期(有可能是您同时登录了太多的客户端)",
"code", HttpStatus.UNAUTHORIZED.value(),
- "timestamp", LocalDateTime.now()
+ "timestamp", new Date()
)));
+
response.flushBuffer();
}
}
\ No newline at end of file
diff --git a/src/main/java/com/zsc/edu/dify/framework/security/SpringSecurityConfig.java b/src/main/java/com/zsc/edu/dify/framework/security/SpringSecurityConfig.java
index 7c09f2d..cf354b0 100644
--- a/src/main/java/com/zsc/edu/dify/framework/security/SpringSecurityConfig.java
+++ b/src/main/java/com/zsc/edu/dify/framework/security/SpringSecurityConfig.java
@@ -10,6 +10,8 @@ import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
+import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.core.userdetails.UserDetailsService;
@@ -20,11 +22,13 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy;
-import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
+import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.session.HttpSessionEventPublisher;
import javax.sql.DataSource;
+import static org.springframework.security.config.Customizer.withDefaults;
+
/**
* @author harry_yao
*/
@@ -39,7 +43,6 @@ public class SpringSecurityConfig {
private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
private final CustomAccessDeniedHandler customAccessDeniedHandler;
private final CustomSessionInformationExpiredStrategy customSessionInformationExpiredStrategy;
-// private final SessionRegistry sessionRegistry;
@Resource
private final DataSource dataSource;
@@ -63,7 +66,7 @@ public class SpringSecurityConfig {
public ConcurrentSessionControlAuthenticationStrategy concurrentSessionControlAuthenticationStrategy() {
ConcurrentSessionControlAuthenticationStrategy concurrentSessionControlAuthenticationStrategy = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry());
concurrentSessionControlAuthenticationStrategy.setMaximumSessions(1);
- concurrentSessionControlAuthenticationStrategy.setExceptionIfMaximumExceeded(true);
+ concurrentSessionControlAuthenticationStrategy.setExceptionIfMaximumExceeded(false);
return concurrentSessionControlAuthenticationStrategy;
}
@@ -126,7 +129,7 @@ public class SpringSecurityConfig {
.ignoringRequestMatchers("v1/**","/api/internal/**", "/api/rest/user/logout","/api/rest/user/register"))
.sessionManagement(session -> session
.maximumSessions(1)
- .maxSessionsPreventsLogin(true)
+ .maxSessionsPreventsLogin(false)
.sessionRegistry(sessionRegistry())
.expiredSessionStrategy(customSessionInformationExpiredStrategy)
).build();
diff --git a/src/main/java/com/zsc/edu/dify/modules/dify/controller/V1ChatController.java b/src/main/java/com/zsc/edu/dify/modules/dify/controller/V1ChatController.java
index 3095ef6..c2f5388 100644
--- a/src/main/java/com/zsc/edu/dify/modules/dify/controller/V1ChatController.java
+++ b/src/main/java/com/zsc/edu/dify/modules/dify/controller/V1ChatController.java
@@ -22,6 +22,7 @@ import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import java.util.List;
+import java.util.Map;
/**
* @author yanghq
@@ -45,6 +46,7 @@ public class V1ChatController {
* apikey 建议在数据库进行存储,前端调用时传智能体 id,从数据库查询
*/
@PostMapping("/completions/{appId}")
+ @PreAuthorize("hasAuthority('difyChat:query')")
@OperationLogAnnotation(content = "'dify对话'", operationType = "发送")
public ChatMessageSendResponse sendChatMessage(
@RequestBody ChatMessageSendRequest sendRequest,
@@ -125,11 +127,12 @@ public class V1ChatController {
*/
@DeleteMapping("/conversation")
@OperationLogAnnotation(content = "'dify对话'", operationType = "删除")
- public void deleteConversation(@RequestParam String conversationId, @RequestParam String appId) {
+ public Map deleteConversation(@RequestParam String conversationId, @RequestParam String appId) {
String apiKey = appEntityService.getApikey(appId);
String userId = SecurityUtil.getUserInfo().id.toString();
try{
difyChat.deleteConversation(conversationId, apiKey, userId);
+ return Map.of("message", "删除成功");
}catch (RuntimeException e){
throw new ApiException("删除会话失败"+e.getMessage());
}
diff --git a/src/main/java/com/zsc/edu/dify/modules/dify/controller/V1ServerController.java b/src/main/java/com/zsc/edu/dify/modules/dify/controller/V1ServerController.java
index 58a5088..9da505e 100644
--- a/src/main/java/com/zsc/edu/dify/modules/dify/controller/V1ServerController.java
+++ b/src/main/java/com/zsc/edu/dify/modules/dify/controller/V1ServerController.java
@@ -139,4 +139,9 @@ public class V1ServerController {
ResponseEntity.ok("关联成功") :
ResponseEntity.status(HttpStatus.BAD_REQUEST).body("关联失败");
}
+
+ @GetMapping("/link/{workflowId}")
+ public List linked(@PathVariable String workflowId) {
+ return workflowDeptService.lambdaQuery().eq(WorkflowDept::getWorkflowId, workflowId).list();
+ }
}
diff --git a/src/main/java/com/zsc/edu/dify/modules/operationLog/controller/OperationController.java b/src/main/java/com/zsc/edu/dify/modules/operationLog/controller/OperationController.java
index 707bada..5fa8700 100644
--- a/src/main/java/com/zsc/edu/dify/modules/operationLog/controller/OperationController.java
+++ b/src/main/java/com/zsc/edu/dify/modules/operationLog/controller/OperationController.java
@@ -24,7 +24,7 @@ public class OperationController {
* 获取操作日志详情
*/
@GetMapping("/{id}")
- @PreAuthorize("hasAuthority('operationLog:query')")
+ @PreAuthorize("hasAuthority('system:operationLog:query')")
public OperationLog crate(@PathVariable("id") Long id) {
return repo.selectById(id);
}
@@ -33,7 +33,7 @@ public class OperationController {
* 获取操作日志分页
*/
@GetMapping("")
- @PreAuthorize("hasAuthority('operationLog:query')")
+ @PreAuthorize("hasAuthority('system:operationLog:query')")
public Page query(Page page, OperationLogQuery query) {
return repo.selectPage(page, query.wrapper());
}
@@ -42,7 +42,7 @@ public class OperationController {
* 批量删除操作日志
*/
@DeleteMapping("/batch")
- @PreAuthorize("hasAuthority('operationLog:delete')")
+ @PreAuthorize("hasAuthority('system:operationLog:delete')")
public int deleteBatch(@RequestBody List ids) {
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
wrapper.in(OperationLog::getId, ids);