Merge remote-tracking branch 'origin/master' into feature/update-dify

This commit is contained in:
vertoryao 2025-06-20 17:10:54 +08:00
commit 95f80df743
7 changed files with 43 additions and 14 deletions

16
pom.xml
View File

@ -132,6 +132,22 @@
<scope>provided</scope>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-data-r2dbc</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>pro.chenggang</groupId>-->
<!-- <artifactId>mybatis-r2dbc-spring</artifactId>-->
<!-- <version>3.0.6.RELEASE</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>pro.chenggang</groupId>-->
<!-- <artifactId>mybatis-r2dbc</artifactId>-->
<!-- <version>3.0.6.RELEASE</version>-->
<!-- </dependency>-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>

View File

@ -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());

View File

@ -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();
}
}

View File

@ -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();

View File

@ -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<String, String> 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());
}

View File

@ -139,4 +139,9 @@ public class V1ServerController {
ResponseEntity.ok("关联成功") :
ResponseEntity.status(HttpStatus.BAD_REQUEST).body("关联失败");
}
@GetMapping("/link/{workflowId}")
public List<WorkflowDept> linked(@PathVariable String workflowId) {
return workflowDeptService.lambdaQuery().eq(WorkflowDept::getWorkflowId, workflowId).list();
}
}

View File

@ -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<OperationLog> query(Page<OperationLog> 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<Long> ids) {
LambdaQueryWrapper<OperationLog> wrapper = new LambdaQueryWrapper<>();
wrapper.in(OperationLog::getId, ids);