refactor(dify): 重构 API 接口和安全配置

- 重构 API接口路径,修改权限命名配置
- 移除了 WebFlux 相关代码,改为使用 Spring Security 配置
This commit is contained in:
vertoryao 2025-04-28 16:15:18 +08:00
parent 54d4e14761
commit 79ed8b3b9c
16 changed files with 136 additions and 325 deletions

18
pom.xml
View File

@ -119,15 +119,15 @@
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency> <!-- <dependency>-->
<groupId>org.springframework.boot</groupId> <!-- <groupId>org.springframework.boot</groupId>-->
<artifactId>spring-boot-starter-data-r2dbc</artifactId> <!-- <artifactId>spring-boot-starter-data-r2dbc</artifactId>-->
</dependency> <!-- </dependency>-->
<dependency> <!-- <dependency>-->
<groupId>io.r2dbc</groupId> <!-- <groupId>io.r2dbc</groupId>-->
<artifactId>r2dbc-postgresql</artifactId> <!-- <artifactId>r2dbc-postgresql</artifactId>-->
<version>0.8.13.RELEASE</version> <!-- <version>0.8.13.RELEASE</version>-->
</dependency> <!-- </dependency>-->
<dependency> <dependency>
<groupId>org.mapstruct</groupId> <groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId> <artifactId>mapstruct</artifactId>

View File

@ -8,7 +8,7 @@ import org.springframework.web.client.RestClient;
* @author zhuang * @author zhuang
*/ */
@Configuration @Configuration
public class AppConfig { public class RestClientConfig {
@Bean @Bean
public RestClient restClient() { public RestClient restClient() {

View File

@ -46,12 +46,12 @@ public class WebMvcConfiguration implements WebMvcConfigurer {
} }
} }
@Override // @Override
public void addCorsMappings(CorsRegistry registry) { // public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // registry.addMapping("/**")
.allowedOrigins("*") // .allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE") // .allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*") // .allowedHeaders("*")
.exposedHeaders("*"); // .exposedHeaders("*");
} // }
} }

View File

@ -4,9 +4,20 @@ import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import jakarta.activation.DataSource;
import jakarta.annotation.Resource;
import org.apache.ibatis.session.ExecutorType;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.naming.Context;
import javax.naming.InitialContext;
/** /**
* @author Yao * @author Yao
@ -14,6 +25,7 @@ import org.springframework.context.annotation.Configuration;
@MapperScan(basePackages = "com.zsc.edu.dify.modules.**.repo") @MapperScan(basePackages = "com.zsc.edu.dify.modules.**.repo")
@Configuration @Configuration
public class MybatisPlusConfig { public class MybatisPlusConfig {
@Bean @Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() { public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
@ -25,4 +37,5 @@ public class MybatisPlusConfig {
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.POSTGRE_SQL)); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.POSTGRE_SQL));
return interceptor; return interceptor;
} }
} }

View File

@ -82,7 +82,7 @@ public class SpringSecurityConfig {
.requestMatchers(HttpMethod.GET, "/api/rest/user/menu","/api/rest/user/register","/api/rest/user/send-email").permitAll() .requestMatchers(HttpMethod.GET, "/api/rest/user/menu","/api/rest/user/register","/api/rest/user/send-email").permitAll()
.requestMatchers(HttpMethod.POST, "/api/rest/user/login","/api/rest/user/register").permitAll() .requestMatchers(HttpMethod.POST, "/api/rest/user/login","/api/rest/user/register").permitAll()
.requestMatchers("/api/rest/user/me").permitAll() .requestMatchers("/api/rest/user/me").permitAll()
.requestMatchers("/v1/**").permitAll() .requestMatchers("/v1/**").authenticated()
.requestMatchers("/api/**").authenticated() .requestMatchers("/api/**").authenticated()
) )
// 不用注解直接通过判断路径实现动态访问权限 // 不用注解直接通过判断路径实现动态访问权限

View File

@ -1,83 +0,0 @@
package com.zsc.edu.dify.framework.security.flux;
import com.zsc.edu.dify.common.util.TreeUtil;
import com.zsc.edu.dify.exception.StateException;
import com.zsc.edu.dify.framework.security.UserDetailsImpl;
import com.zsc.edu.dify.modules.system.entity.Dept;
import com.zsc.edu.dify.modules.system.entity.Menu;
import com.zsc.edu.dify.modules.system.entity.Role;
import com.zsc.edu.dify.modules.system.entity.UserRole;
import com.zsc.edu.dify.modules.system.repo.flux.*;
import com.zsc.edu.dify.modules.system.service.DeptService;
import lombok.AllArgsConstructor;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author zhuang
*/
@AllArgsConstructor
@Service
public class FluxUserDetailServiceImpl implements ReactiveUserDetailsService {
private final UserFluxRepository userRepo;
private final MenuFluxRepository menuRepository;
private final RoleFluxRepository roleFluxRepository;
private final UserRoleFluxRepository userRoleFluxRepository;
private final DeptService deptService;
@Override
public Mono<UserDetails> findByUsername(String username) {
return userRepo.findByUsername(username)
.flatMap(user -> {
if (!user.getEnableState()) {
return Mono.error(new StateException("用户 '" + username + "' 已被禁用!请联系管理员"));
}
// 先获取UserRole列表并从中提取roleIds
return userRoleFluxRepository.findByUserId(user.getId()).collectList()
.flatMap(userRoles -> Mono.zip(
roleFluxRepository.findByDeptId(user.getDeptId()),
deptService.listFluxTree(user.getDeptId()),
menuRepository.findByRoleId(user.getRoleId())
))
.flatMap(tuple -> {
Role role = (Role) tuple.getT1();
List<Dept> depts = (List<Dept>) tuple.getT2();
List<Menu> menus = tuple.getT3();
user.setRole(role);
Set<Long> dataScopeDeptIds = depts.stream()
.map(Dept::getId)
.collect(Collectors.toSet());
user.setDataScopeDeptIds(dataScopeDeptIds);
Set<String> permissions = menus.stream()
.map(Menu::getPermissions)
.collect(Collectors.toSet());
return Mono.just(UserDetailsImpl.from(user, permissions));
});
});
}
// @Override
// public Mono<UserDetails> findByUsername(String username) {
// return userRepo.findByUsername(username)
// .flatMap(user -> menuRepository.findByRoleId(user.getRoleId())
// .map(ids-> userRoleFluxRepository.findByUserId(user.getId()))
// .map(roles-> roleFluxRepository.findByIdIn(ids))
// .map(menus -> {
// Set<String> permissions = menus.stream().map(Menu::getPermissions).collect(Collectors.toSet());
// return UserDetailsImpl.from(user, permissions);
// })
// );
// }
}

View File

@ -1,102 +0,0 @@
package com.zsc.edu.dify.framework.security.flux;
import com.zsc.edu.dify.framework.security.*;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
import org.springframework.security.web.server.authentication.ServerAuthenticationEntryPointFailureHandler;
import org.springframework.security.web.server.authentication.ServerAuthenticationSuccessHandler;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler;
import org.springframework.security.web.server.context.WebSessionServerSecurityContextRepository;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsConfigurationSource;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import reactor.core.publisher.Mono;
import javax.sql.DataSource;
@EnableWebFluxSecurity
@AllArgsConstructor
@Configuration
public class SpringWebFluxSecurityConfig {
private final ReactiveUserDetailsService userDetailsService;
private final CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
private final CustomAccessDeniedHandler customAccessDeniedHandler;
private final SecurityBeanConfig securityBeanConfig;
@Bean
public ReactiveAuthenticationManager reactiveAuthenticationManager() {
UserDetailsRepositoryReactiveAuthenticationManager authenticationManager =
new UserDetailsRepositoryReactiveAuthenticationManager(userDetailsService);
authenticationManager.setPasswordEncoder(securityBeanConfig.passwordEncoder());
return authenticationManager;
}
@Bean
public ReactiveAuthorizationManager<AuthorizationContext> reactiveAuthorizationManager() {
return (authenticationMono, context) -> authenticationMono
.flatMap(authentication ->
userDetailsService.findByUsername(authentication.getName())
.map(userDetails -> {
SecurityUtil.setUserInfo((UserDetailsImpl) userDetails);
return new AuthorizationDecision(true);
})
)
.defaultIfEmpty(new AuthorizationDecision(false));
}
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
// 配置认证过滤器
AuthenticationWebFilter authenticationFilter = new AuthenticationWebFilter(reactiveAuthenticationManager());
authenticationFilter.setAuthenticationSuccessHandler((ServerAuthenticationSuccessHandler) customAuthenticationSuccessHandler);
authenticationFilter.setAuthenticationFailureHandler(new ServerAuthenticationEntryPointFailureHandler((ServerAuthenticationEntryPoint) customAuthenticationEntryPoint));
authenticationFilter.setSecurityContextRepository(new WebSessionServerSecurityContextRepository());
return http
.authorizeExchange(exchanges -> exchanges
.pathMatchers("/v1/flux/**").access(reactiveAuthorizationManager()) // 通过自定义权限管理器进行权限校验
.anyExchange().authenticated()
)
.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION)
.exceptionHandling(handling -> handling
.authenticationEntryPoint((ServerAuthenticationEntryPoint) customAuthenticationEntryPoint)
.accessDeniedHandler((ServerAccessDeniedHandler) customAccessDeniedHandler)
)
.csrf(ServerHttpSecurity.CsrfSpec::disable)
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
.httpBasic(ServerHttpSecurity.HttpBasicSpec::disable)
.build();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/v1/flux/**", config);
return source;
}
}

View File

@ -5,6 +5,7 @@ import io.github.guoshiqiufeng.dify.chat.DifyChat;
import io.github.guoshiqiufeng.dify.chat.dto.request.ChatMessageSendRequest; import io.github.guoshiqiufeng.dify.chat.dto.request.ChatMessageSendRequest;
import io.github.guoshiqiufeng.dify.chat.dto.request.MessageConversationsRequest; import io.github.guoshiqiufeng.dify.chat.dto.request.MessageConversationsRequest;
import io.github.guoshiqiufeng.dify.chat.dto.response.ChatMessageSendCompletionResponse; import io.github.guoshiqiufeng.dify.chat.dto.response.ChatMessageSendCompletionResponse;
import io.github.guoshiqiufeng.dify.chat.dto.response.ChatMessageSendResponse;
import io.github.guoshiqiufeng.dify.chat.dto.response.MessageConversationsResponse; import io.github.guoshiqiufeng.dify.chat.dto.response.MessageConversationsResponse;
import io.github.guoshiqiufeng.dify.core.pojo.DifyPageResult; import io.github.guoshiqiufeng.dify.core.pojo.DifyPageResult;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
@ -12,6 +13,7 @@ import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/** /**
* @author yanghq * @author yanghq
@ -27,6 +29,25 @@ public class V1ChatController {
@Resource @Resource
private AppEntityRepository appEntityRepository; private AppEntityRepository appEntityRepository;
/**
* 发送消息
*
* @param sendRequest 消息参数 可以自定义参数调用 difyChat 实例时重新组装即可
* 用户 id可以改为从上下文token获取
* apikey 建议在数据库进行存储前端调用时传智能体 id从数据库查询
*/
@PostMapping("/completions/{appid}")
@PreAuthorize("hasAuthority('dify:chat:query')")
public ChatMessageSendResponse sendChatMessage(
@RequestBody ChatMessageSendRequest sendRequest,
@PathVariable String appid
) {
String apiKey = appEntityRepository.selectApiKey(appid);
sendRequest.setApiKey(apiKey);
return difyChat.send(sendRequest);
}
/** /**
* 发送消息流式 * 发送消息流式
* *
@ -34,10 +55,14 @@ public class V1ChatController {
* 用户 id可以改为从上下文token获取 * 用户 id可以改为从上下文token获取
* apikey 建议在数据库进行存储前端调用时传智能体 id从数据库查询 * apikey 建议在数据库进行存储前端调用时传智能体 id从数据库查询
*/ */
@PostMapping(value = "/completions/{appId}", produces = MediaType.TEXT_EVENT_STREAM_VALUE) @PostMapping(value = "/completions/stream/{appid}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
@PreAuthorize("hasAuthority('difyChat:query')") // @PreAuthorize("hasAuthority('difyChat:query')")
public Flux<ChatMessageSendCompletionResponse> sendChatMessageStream(@RequestBody ChatMessageSendRequest sendRequest, @PathVariable String appId) { public Flux<ChatMessageSendCompletionResponse> sendChatMessageStream(
sendRequest.setApiKey(appEntityRepository.selectApiKey(appId)); @RequestBody ChatMessageSendRequest sendRequest,
@PathVariable String appid
) {
String apiKey = appEntityRepository.selectApiKey(appid);
sendRequest.setApiKey(apiKey);
return difyChat.sendChatMessageStream(sendRequest); return difyChat.sendChatMessageStream(sendRequest);
} }
@ -47,10 +72,14 @@ public class V1ChatController {
* @param request 请求参数 * @param request 请求参数
* @return 会话列表 * @return 会话列表
*/ */
@PostMapping("/conversations") @PostMapping("/conversations/{appid}")
@PreAuthorize("hasAuthority('difyChat:query')") @PreAuthorize("hasAuthority('dify:chat:query')")
public DifyPageResult<MessageConversationsResponse> conversations(@RequestBody MessageConversationsRequest request) { public DifyPageResult<MessageConversationsResponse> conversations(
request.setApiKey("app-mM2UGTE5QVPLCwGvwifnV0g7"); @RequestBody MessageConversationsRequest request,
@PathVariable String appid
) {
String apiKey = appEntityRepository.selectApiKey(appid);
request.setApiKey(apiKey);
return difyChat.conversations(request); return difyChat.conversations(request);
} }
@ -60,10 +89,10 @@ public class V1ChatController {
* @param taskId 任务id * @param taskId 任务id
* @param userId 用户id * @param userId 用户id
*/ */
@PatchMapping("/stopMessagesStream") @PatchMapping("/stream/stop")
@PreAuthorize("hasAuthority('difyChat:update')") public void stopMessagesStream(@RequestParam String taskId, @RequestParam String userId, @RequestParam String appid) {
public void stopMessagesStream( String taskId, String userId) { String apiKey = appEntityRepository.selectApiKey(appid);
difyChat.stopMessagesStream("app-mM2UGTE5QVPLCwGvwifnV0g7", taskId, userId); difyChat.stopMessagesStream(apiKey, taskId, userId);
} }
/** /**
@ -72,9 +101,10 @@ public class V1ChatController {
* @param conversationId 会话id * @param conversationId 会话id
* @param userId 用户id * @param userId 用户id
*/ */
@DeleteMapping("/messages/suggested") @DeleteMapping("/conversation")
@PreAuthorize("hasAuthority('difyChat:delete')") @PreAuthorize("hasAuthority('dify:chat:delete')")
public void deleteConversation(String conversationId, String userId) { public void deleteConversation(@RequestParam String conversationId, @RequestParam String userId, @RequestParam String appid) {
difyChat.deleteConversation(conversationId, "app-mM2UGTE5QVPLCwGvwifnV0g7", userId); String apiKey = appEntityRepository.selectApiKey(appid);
difyChat.deleteConversation(conversationId, apiKey, userId);
} }
} }

View File

@ -5,6 +5,7 @@ import io.github.guoshiqiufeng.dify.dataset.DifyDataset;
import io.github.guoshiqiufeng.dify.dataset.dto.request.*; import io.github.guoshiqiufeng.dify.dataset.dto.request.*;
import io.github.guoshiqiufeng.dify.dataset.dto.response.*; import io.github.guoshiqiufeng.dify.dataset.dto.response.*;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -14,6 +15,9 @@ public class V1DatasetController {
@Resource @Resource
private DifyDataset difyDataset; private DifyDataset difyDataset;
@Value("${dify.dataset.api-key}")
private String apiKey;
/** /**
* 分页查询知识库 * 分页查询知识库
* *
@ -21,9 +25,9 @@ public class V1DatasetController {
* @return * @return
*/ */
@PostMapping("/page") @PostMapping("/page")
@PreAuthorize("hasAuthority('difyDataSet:query')") @PreAuthorize("hasAuthority('dify:dataset:query')")
public DifyPageResult<DatasetResponse> page(@RequestBody DatasetPageRequest request){ public DifyPageResult<DatasetResponse> page(@RequestBody DatasetPageRequest request){
request.setApiKey("dataset-kN5WTJ8jR877YfN1A34JceVg"); request.setApiKey(apiKey);
return difyDataset.page(request); return difyDataset.page(request);
} }
@ -34,7 +38,7 @@ public class V1DatasetController {
* @return * @return
*/ */
@PostMapping("/createDocumentByFile") @PostMapping("/createDocumentByFile")
@PreAuthorize("hasAuthority('difyDataSet:create')") @PreAuthorize("hasAuthority('dify:dataset:create')")
public DocumentCreateResponse createDocumentByFile(DocumentCreateByFileRequest request){ public DocumentCreateResponse createDocumentByFile(DocumentCreateByFileRequest request){
return difyDataset.createDocumentByFile(request); return difyDataset.createDocumentByFile(request);
} }
@ -46,9 +50,9 @@ public class V1DatasetController {
* @return * @return
*/ */
@GetMapping("/pageDocument") @GetMapping("/pageDocument")
@PreAuthorize("hasAuthority('difyDataSet:query')") @PreAuthorize("hasAuthority('dify:dataset:query')")
public DifyPageResult<DocumentInfo> pageDocument(@RequestBody DatasetPageDocumentRequest request){ public DifyPageResult<DocumentInfo> pageDocument(@RequestBody DatasetPageDocumentRequest request){
request.setApiKey("dataset-kN5WTJ8jR877YfN1A34JceVg"); request.setApiKey(apiKey);
return difyDataset.pageDocument(request); return difyDataset.pageDocument(request);
} }
@ -60,9 +64,9 @@ public class V1DatasetController {
* @return * @return
*/ */
@PostMapping("/uploadFileInfo") @PostMapping("/uploadFileInfo")
@PreAuthorize("hasAuthority('difyDataSet:query')") @PreAuthorize("hasAuthority('dify:dataset:query')")
public UploadFileInfoResponse uploadFileInfo(String datasetId, String documentId){ public UploadFileInfoResponse uploadFileInfo(String datasetId, String documentId){
return difyDataset.uploadFileInfo(datasetId, documentId,"dataset-kN5WTJ8jR877YfN1A34JceVg"); return difyDataset.uploadFileInfo(datasetId, documentId,apiKey);
} }
/** /**
@ -73,9 +77,9 @@ public class V1DatasetController {
* @return * @return
*/ */
@DeleteMapping("/deleteDocument") @DeleteMapping("/deleteDocument")
@PreAuthorize("hasAuthority('difyDataSet:delete')") @PreAuthorize("hasAuthority('dify:dataset:delete')")
public DocumentDeleteResponse deleteDocument(String datasetId, String documentId){ public DocumentDeleteResponse deleteDocument(String datasetId, String documentId){
return difyDataset.deleteDocument(datasetId, documentId, "app-mM2UGTE5QVPLCwGvwifnV0g7"); return difyDataset.deleteDocument(datasetId, documentId, apiKey);
} }
/** /**
@ -85,7 +89,7 @@ public class V1DatasetController {
* @return * @return
*/ */
@PostMapping("/createSegment") @PostMapping("/createSegment")
@PreAuthorize("hasAuthority('difyDataSet:create')") @PreAuthorize("hasAuthority('dify:dataset:create')")
public SegmentResponse createSegment(@RequestBody SegmentCreateRequest request){ public SegmentResponse createSegment(@RequestBody SegmentCreateRequest request){
return difyDataset.createSegment(request); return difyDataset.createSegment(request);
} }
@ -97,7 +101,7 @@ public class V1DatasetController {
* @return * @return
*/ */
@PostMapping("/createSegmentChildChunk") @PostMapping("/createSegmentChildChunk")
@PreAuthorize("hasAuthority('difyDataSet:create')") @PreAuthorize("hasAuthority('dify:dataset:create')")
public SegmentChildChunkCreateResponse createSegmentChildChunk(@RequestBody SegmentChildChunkCreateRequest request){ public SegmentChildChunkCreateResponse createSegmentChildChunk(@RequestBody SegmentChildChunkCreateRequest request){
return difyDataset.createSegmentChildChunk(request); return difyDataset.createSegmentChildChunk(request);
} }
@ -109,7 +113,7 @@ public class V1DatasetController {
* @return * @return
*/ */
@GetMapping("/retrieve") @GetMapping("/retrieve")
@PreAuthorize("hasAuthority('difyDataSet:query')") @PreAuthorize("hasAuthority('dify:dataset:query')")
public RetrieveResponse retrieve(@RequestBody RetrieveRequest request){ public RetrieveResponse retrieve(@RequestBody RetrieveRequest request){
return difyDataset.retrieve(request); return difyDataset.retrieve(request);
} }

View File

@ -31,7 +31,7 @@ public class V1ServerController {
* @return * @return
*/ */
@GetMapping("/apps") @GetMapping("/apps")
@PreAuthorize("hasAuthority('difyServer:query')") @PreAuthorize("hasAuthority('dify:server:query')")
public List<AppsResponseVO> getApps(String mode, String name) { public List<AppsResponseVO> getApps(String mode, String name) {
return difyServerService.getApps(mode, name); return difyServerService.getApps(mode, name);
} }
@ -42,7 +42,7 @@ public class V1ServerController {
* @return * @return
*/ */
@GetMapping("/{id}") @GetMapping("/{id}")
@PreAuthorize("hasAuthority('difyServer:query')") @PreAuthorize("hasAuthority('dify:server:query')")
public AppsResponseVO getApp(@PathVariable("id") String id) { public AppsResponseVO getApp(@PathVariable("id") String id) {
return difyServer.app(id); return difyServer.app(id);
} }
@ -53,7 +53,7 @@ public class V1ServerController {
* @return * @return
*/ */
@GetMapping("/api-key/{id}") @GetMapping("/api-key/{id}")
@PreAuthorize("hasAuthority('difyServer:query')") @PreAuthorize("hasAuthority('dify:server:query')")
public List<ApiKeyResponseVO> getAppApiKey(@PathVariable("id") String id) { public List<ApiKeyResponseVO> getAppApiKey(@PathVariable("id") String id) {
return difyServer.getAppApiKey(id); return difyServer.getAppApiKey(id);
} }
@ -64,7 +64,7 @@ public class V1ServerController {
* @return * @return
*/ */
@PostMapping("/api-key/init/{id}") @PostMapping("/api-key/init/{id}")
@PreAuthorize("hasAuthority('difyServer:create')") @PreAuthorize("hasAuthority('dify:server:create')")
public List<ApiKeyResponseVO> initAppApiKey(@PathVariable("id") String id) { public List<ApiKeyResponseVO> initAppApiKey(@PathVariable("id") String id) {
return difyServer.initAppApiKey(id); return difyServer.initAppApiKey(id);
} }
@ -74,7 +74,7 @@ public class V1ServerController {
* @return * @return
*/ */
@GetMapping("/api-key/dataset") @GetMapping("/api-key/dataset")
@PreAuthorize("hasAuthority('difyServer:query')") @PreAuthorize("hasAuthority('dify:server:query')")
public List<DatasetApiKeyResponseVO> getDatasetApiKey() { public List<DatasetApiKeyResponseVO> getDatasetApiKey() {
return difyServer.getDatasetApiKey(); return difyServer.getDatasetApiKey();
} }
@ -84,7 +84,7 @@ public class V1ServerController {
* @return * @return
*/ */
@PostMapping("/api-key/dataset/init") @PostMapping("/api-key/dataset/init")
@PreAuthorize("hasAuthority('difyServer:create')") @PreAuthorize("hasAuthority('dify:server:create')")
public List<DatasetApiKeyResponseVO> initDatasetApiKey() { public List<DatasetApiKeyResponseVO> initDatasetApiKey() {
return difyServer.initDatasetApiKey(); return difyServer.initDatasetApiKey();
} }
@ -95,8 +95,8 @@ public class V1ServerController {
* @param id 应用id * @param id 应用id
* @return * @return
*/ */
@PostMapping("/app/{id}") @PostMapping("/app/{id}/toggle")
@PreAuthorize("hasAuthority('difyServer:update')") @PreAuthorize("hasAuthority('dify:server:update')")
public boolean enabledApp(@PathVariable String id) { public boolean enabledApp(@PathVariable String id) {
return difyServerService.enabledApp(id); return difyServerService.enabledApp(id);
} }
@ -105,9 +105,9 @@ public class V1ServerController {
* 获取可用应用列表 * 获取可用应用列表
* @return * @return
*/ */
@GetMapping("/apps/able") @GetMapping("/apps/enabled")
@PreAuthorize("hasAuthority('difyServer:query')") @PreAuthorize("hasAuthority('dify:server:query')")
public List<AppEntity> getAbleApps() { public List<AppEntity> getEnableApps() {
LambdaQueryWrapper<AppEntity> queryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<AppEntity> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(AppEntity::isEnabled, true); queryWrapper.eq(AppEntity::isEnabled, true);
return difyServerService.list(queryWrapper); return difyServerService.list(queryWrapper);

View File

@ -1,5 +1,6 @@
package com.zsc.edu.dify.modules.dify.controller; package com.zsc.edu.dify.modules.dify.controller;
import com.zsc.edu.dify.modules.dify.repo.AppEntityRepository;
import io.github.guoshiqiufeng.dify.core.pojo.DifyPageResult; import io.github.guoshiqiufeng.dify.core.pojo.DifyPageResult;
import io.github.guoshiqiufeng.dify.workflow.DifyWorkflow; import io.github.guoshiqiufeng.dify.workflow.DifyWorkflow;
import io.github.guoshiqiufeng.dify.workflow.dto.request.WorkflowLogsRequest; import io.github.guoshiqiufeng.dify.workflow.dto.request.WorkflowLogsRequest;
@ -11,22 +12,27 @@ import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
@RestController @RestController
@RequestMapping("/v1/work") @RequestMapping("/v1/workflow")
public class V1WorkflowController { public class V1WorkflowController {
@Resource @Resource
private DifyWorkflow difyWorkflow; private DifyWorkflow difyWorkflow;
@Resource
private AppEntityRepository appEntityRepository;
/** /**
* 运行工作流 * 运行工作流
* *
* @param request * @param request
* @return * @return
*/ */
@PostMapping("/run") @PostMapping("/run/{appId}")
@PreAuthorize("hasAuthority('difyWorkFlow:query')") @PreAuthorize("hasAuthority('dify:workflow:run')")
public WorkflowRunResponse runWorkflow(@RequestBody WorkflowRunRequest request) { public WorkflowRunResponse runWorkflow(@RequestBody WorkflowRunRequest request,@PathVariable String appId) {
request.setApiKey("app-ZpkQM6yy767oUTfNSBYq65nB"); String apiKey = appEntityRepository.selectApiKey(appId);
request.setApiKey(apiKey);
return difyWorkflow.runWorkflow(request); return difyWorkflow.runWorkflow(request);
} }
@ -38,7 +44,6 @@ public class V1WorkflowController {
*/ */
@PostMapping("/run/stream") @PostMapping("/run/stream")
public Flux<WorkflowRunStreamResponse> runWorkflowStream(@RequestBody WorkflowRunRequest request) { public Flux<WorkflowRunStreamResponse> runWorkflowStream(@RequestBody WorkflowRunRequest request) {
request.setApiKey("app-ZpkQM6yy767oUTfNSBYq65nB");
return difyWorkflow.runWorkflowStream(request); return difyWorkflow.runWorkflowStream(request);
} }
@ -49,9 +54,10 @@ public class V1WorkflowController {
* @param userId * @param userId
* @return * @return
*/ */
@PatchMapping("/stop") @PatchMapping("/stop/{appId}")
public WorkflowStopResponse stopWorkflowStream( String taskId, String userId){ public WorkflowStopResponse stopWorkflowStream( String taskId, String userId, @PathVariable String appId) {
return difyWorkflow.stopWorkflowStream("app-mM2UGTE5QVPLCwGvwifnV0g7", taskId, userId); String apiKey = appEntityRepository.selectApiKey(appId);
return difyWorkflow.stopWorkflowStream(apiKey, taskId, userId);
} }
/** /**
@ -60,10 +66,11 @@ public class V1WorkflowController {
* @param workflowRunId * @param workflowRunId
* @return * @return
*/ */
@GetMapping("/info") @GetMapping("/info/{appId}")
@PreAuthorize("hasAuthority('difyWorkFlow:query')") @PreAuthorize("hasAuthority('dify:workflow:info')")
public WorkflowInfoResponse info(String workflowRunId) { public WorkflowInfoResponse info(String workflowRunId, @PathVariable String appId) {
return difyWorkflow.info(workflowRunId, "app-ZpkQM6yy767oUTfNSBYq65nB"); String apiKey = appEntityRepository.selectApiKey(appId);
return difyWorkflow.info(workflowRunId, apiKey);
} }
/** /**
@ -72,10 +79,11 @@ public class V1WorkflowController {
* @param request * @param request
* @return * @return
*/ */
@PostMapping("/logs") @PostMapping("/logs/{appId}")
@PreAuthorize("hasAuthority('difyWorkFlow:query')") @PreAuthorize("hasAuthority('difyWorkFlow:log')")
public DifyPageResult<WorkflowLogs> logs(@RequestBody WorkflowLogsRequest request) { public DifyPageResult<WorkflowLogs> logs(@RequestBody WorkflowLogsRequest request, @PathVariable String appId) {
request.setApiKey("app-ZpkQM6yy767oUTfNSBYq65nB"); String apiKey = appEntityRepository.selectApiKey(appId);
request.setApiKey(apiKey);
return difyWorkflow.logs(request); return difyWorkflow.logs(request);
} }
} }

View File

@ -1,16 +0,0 @@
package com.zsc.edu.dify.modules.system.repo.flux;
import com.zsc.edu.dify.modules.system.entity.Menu;
import org.springframework.data.r2dbc.repository.Query;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.List;
@Repository
public interface MenuFluxRepository extends ReactiveCrudRepository<Menu,Long> {
@Query("select * from sys_menu where id in (select menu_id from sys_roles_menus where role_id = :roleId)")
Mono<List<Menu>> findByRoleId(Long roleId);
}

View File

@ -1,15 +0,0 @@
package com.zsc.edu.dify.modules.system.repo.flux;
import com.zsc.edu.dify.modules.system.entity.Role;
import org.mapstruct.Mapper;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Mono;
import java.util.List;
@Repository
public interface RoleFluxRepository extends ReactiveCrudRepository<Role,Long> {
Mono<?> findByDeptId(Long id);
}

View File

@ -1,12 +0,0 @@
package com.zsc.edu.dify.modules.system.repo.flux;
import com.zsc.edu.dify.modules.system.entity.User;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Mono;
@Repository
public interface UserFluxRepository extends ReactiveCrudRepository<User,Long> {
Mono<User> findByUsername(String username);
}

View File

@ -1,16 +0,0 @@
package com.zsc.edu.dify.modules.system.repo.flux;
import com.zsc.edu.dify.modules.system.entity.UserRole;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.List;
@Repository
public interface UserRoleFluxRepository extends ReactiveCrudRepository<UserRole,Long> {
Flux<List<Long>> findByUserId(Long userId);
}

View File

@ -11,12 +11,12 @@ mybatis-plus:
map-underscore-to-camel-case: true map-underscore-to-camel-case: true
spring: spring:
main: # main:
allow-bean-definition-overriding: true # allow-bean-definition-overriding: true
r2dbc: # r2dbc:
url: r2dbc:postgresql://43.139.10.64:15432/dify?ssl=false&TimeZone=Asia/Shanghai # url: r2dbc:postgresql://43.139.10.64:15432/dify?ssl=false&TimeZone=Asia/Shanghai
username: gitea # username: gitea
password: gitea # password: gitea
datasource: datasource:
url: jdbc:postgresql://43.139.10.64:15432/dify?ssl=false&TimeZone=Asia/Shanghai url: jdbc:postgresql://43.139.10.64:15432/dify?ssl=false&TimeZone=Asia/Shanghai
username: gitea username: gitea