This commit is contained in:
tanglong 2026-07-31 16:59:16 +08:00
parent 5e2c493e5b
commit 3df5893e31
2 changed files with 55 additions and 0 deletions

View File

@ -20,6 +20,7 @@ import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.Set;
@ -70,6 +71,8 @@ public class AssistantApiController {
String userId = resolveUserId(request, httpRequest);
if (query.isEmpty()) return AssistantQueryResponse.failure("query不能为空");
if (userId.isEmpty()) {
log.warn("assistant sports venue missing WeCom UserID identityHeaders={}",
identityHeaderNames(httpRequest));
return AssistantQueryResponse.failure(
"未能从企业微信调用上下文获取UserID,暂时无法判断数据权限。");
}
@ -149,6 +152,24 @@ public class AssistantApiController {
String value = httpRequest.getHeader(headerName);
if (value != null && !value.isBlank()) return value.trim();
}
Enumeration<String> requestHeaderNames = httpRequest.getHeaderNames();
while (requestHeaderNames != null && requestHeaderNames.hasMoreElements()) {
String headerName = requestHeaderNames.nextElement();
String normalizedName = headerName
.toLowerCase(Locale.ROOT)
.replace("-", "")
.replace("_", "");
if (!normalizedName.contains("userid")) continue;
String value = httpRequest.getHeader(headerName);
if (value != null && !value.isBlank()) return value.trim();
}
String parameterUserId = httpRequest.getParameter("userid");
if (parameterUserId == null || parameterUserId.isBlank()) {
parameterUserId = httpRequest.getParameter("userId");
}
if (parameterUserId != null && !parameterUserId.isBlank()) {
return parameterUserId.trim();
}
if (httpRequest.getUserPrincipal() != null
&& httpRequest.getUserPrincipal().getName() != null
&& !httpRequest.getUserPrincipal().getName().isBlank()) {
@ -156,4 +177,20 @@ public class AssistantApiController {
}
return request == null ? "" : request.normalizedUserId();
}
private List<String> identityHeaderNames(HttpServletRequest httpRequest) {
List<String> names = new ArrayList<>();
Enumeration<String> values = httpRequest.getHeaderNames();
while (values != null && values.hasMoreElements()) {
String name = values.nextElement();
String normalized = name.toLowerCase(Locale.ROOT);
if (normalized.contains("user")
|| normalized.contains("wecom")
|| normalized.contains("wework")
|| normalized.startsWith("wx")) {
names.add(name);
}
}
return List.copyOf(names);
}
}

View File

@ -129,6 +129,24 @@ class AssistantApiControllerTest {
.andExpect(jsonPath("$.success").value(true));
}
@Test
void sportsVenueApiRecognizesPrefixedWecomUserIdHeader() throws Exception {
SemanticDispatchService semantic = mock(SemanticDispatchService.class);
when(semantic.dispatchWithAttachments("YiNianYiQingJing", "客资日报"))
.thenReturn(new SemanticDispatchResult("客资日报结果", List.of()));
MockMvc mvc = mvc(
mock(CozeWorkflowService.class),
semantic,
new AssistantFileStore());
mvc.perform(post("/api/assistant/sports-venue/query/")
.header("X-WeCom-From-UserId", "YiNianYiQingJing")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"query\":\"客资日报\"}"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true));
}
@Test
void sportsVenueApiRejectsRequestWhenWecomContextHasNoUserId() throws Exception {
MockMvc mvc = mvc(