fix: 修复开放接口鉴权与小程序联调配置

- 注册小程序租户过滤器并放宽 /api/open 路径匹配

- 移除全局异常吞没逻辑并修复律师列表筛选空值处理

- 统一小程序 develop、trial、release 环境接口域名
This commit is contained in:
2026-03-21 11:18:04 +08:00
parent 728847a8e3
commit ac7eb6d85d
5 changed files with 30 additions and 17 deletions

View File

@@ -5,6 +5,7 @@ import com.easycard.common.auth.JwtTokenService;
import com.easycard.common.auth.LoginUser; import com.easycard.common.auth.LoginUser;
import com.easycard.common.tenant.TenantContext; import com.easycard.common.tenant.TenantContext;
import com.easycard.common.tenant.TenantContextHolder; import com.easycard.common.tenant.TenantContextHolder;
import com.easycard.module.tenant.web.MiniappTenantContextFilter;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.FilterChain; import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
@@ -83,7 +84,8 @@ public class SecurityConfig {
@Bean @Bean
public SecurityFilterChain securityFilterChain( public SecurityFilterChain securityFilterChain(
HttpSecurity http, HttpSecurity http,
JwtAuthenticationFilter jwtAuthenticationFilter JwtAuthenticationFilter jwtAuthenticationFilter,
MiniappTenantContextFilter miniappTenantContextFilter
) throws Exception { ) throws Exception {
http http
.csrf(AbstractHttpConfigurer::disable) .csrf(AbstractHttpConfigurer::disable)
@@ -108,6 +110,7 @@ public class SecurityConfig {
response.setContentType(MediaType.APPLICATION_JSON_VALUE); response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.getWriter().write("{\"code\":\"UNAUTHORIZED\",\"message\":\"未登录或登录已失效\",\"data\":null}"); response.getWriter().write("{\"code\":\"UNAUTHORIZED\",\"message\":\"未登录或登录已失效\",\"data\":null}");
})) }))
.addFilterBefore(miniappTenantContextFilter, UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.cors(Customizer.withDefaults()); .cors(Customizer.withDefaults());
return http.build(); return http.build();
@@ -128,7 +131,10 @@ class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override @Override
protected boolean shouldNotFilter(HttpServletRequest request) { protected boolean shouldNotFilter(HttpServletRequest request) {
String uri = request.getRequestURI(); String uri = request.getRequestURI();
return uri.startsWith("/api/open/") || "/api/v1/auth/login".equals(uri); if (uri == null) {
return false;
}
return uri.contains("/api/open/") || uri.endsWith("/api/v1/auth/login");
} }
@Override @Override

View File

@@ -32,9 +32,4 @@ public class GlobalExceptionHandler {
public ApiResponse<Void> handleMaxUploadSizeExceededException(MaxUploadSizeExceededException exception) { public ApiResponse<Void> handleMaxUploadSizeExceededException(MaxUploadSizeExceededException exception) {
return ApiResponse.fail("FILE_TOO_LARGE", "上传图片不能超过 5MB"); return ApiResponse.fail("FILE_TOO_LARGE", "上传图片不能超过 5MB");
} }
@ExceptionHandler(Exception.class)
public ApiResponse<Void> handleException(Exception exception) {
return ApiResponse.fail("INTERNAL_SERVER_ERROR", exception.getMessage());
}
} }

View File

@@ -343,18 +343,21 @@ public class CardProfileService {
Map<Long, List<String>> specialtyMap = loadSpecialtyMap(cards.stream().map(CardProfileDO::getId).toList()); Map<Long, List<String>> specialtyMap = loadSpecialtyMap(cards.stream().map(CardProfileDO::getId).toList());
return cards.stream() return cards.stream()
.filter(card -> { .filter(card -> {
String deptName = deptMap.containsKey(card.getDeptId()) ? deptMap.get(card.getDeptId()).getDeptName() : ""; OrgDepartmentDO department = card.getDeptId() == null ? null : deptMap.get(card.getDeptId());
String deptName = department == null ? "" : department.getDeptName();
List<String> specialties = specialtyMap.getOrDefault(card.getId(), List.of()); List<String> specialties = specialtyMap.getOrDefault(card.getId(), List.of());
boolean keywordMatched = !StringUtils.hasText(keyword) boolean keywordMatched = !StringUtils.hasText(keyword)
|| card.getCardName().contains(keyword) || containsText(card.getCardName(), keyword)
|| deptName.contains(keyword) || containsText(deptName, keyword)
|| specialties.stream().anyMatch(item -> item.contains(keyword)); || specialties.stream().anyMatch(item -> containsText(item, keyword));
boolean officeMatched = !StringUtils.hasText(office) || office.equals(deptName); boolean officeMatched = !StringUtils.hasText(office) || office.equals(deptName);
boolean areaMatched = !StringUtils.hasText(practiceArea) || specialties.stream().anyMatch(item -> item.equals(practiceArea)); boolean areaMatched = !StringUtils.hasText(practiceArea)
|| specialties.stream().anyMatch(item -> equalsText(item, practiceArea));
return keywordMatched && officeMatched && areaMatched; return keywordMatched && officeMatched && areaMatched;
}) })
.map(card -> { .map(card -> {
String deptName = deptMap.containsKey(card.getDeptId()) ? deptMap.get(card.getDeptId()).getDeptName() : ""; OrgDepartmentDO department = card.getDeptId() == null ? null : deptMap.get(card.getDeptId());
String deptName = department == null ? "" : department.getDeptName();
return new OpenCardListItem( return new OpenCardListItem(
card.getId(), card.getId(),
card.getCardName(), card.getCardName(),
@@ -496,6 +499,14 @@ public class CardProfileService {
return AUTO_MANAGED_ROLE_CODE.equals(roleCode); return AUTO_MANAGED_ROLE_CODE.equals(roleCode);
} }
private boolean containsText(String source, String keyword) {
return source != null && keyword != null && source.contains(keyword);
}
private boolean equalsText(String left, String right) {
return left != null && left.equals(right);
}
private SysUserDO createHiddenLawyerUser(LoginUser loginUser, UpsertCardRequest request) { private SysUserDO createHiddenLawyerUser(LoginUser loginUser, UpsertCardRequest request) {
SysRoleDO role = getRequiredTenantRole(loginUser.tenantId(), AUTO_MANAGED_ROLE_CODE); SysRoleDO role = getRequiredTenantRole(loginUser.tenantId(), AUTO_MANAGED_ROLE_CODE);
SysUserDO user = new SysUserDO(); SysUserDO user = new SysUserDO();

View File

@@ -33,7 +33,8 @@ public class MiniappTenantContextFilter extends OncePerRequestFilter {
@Override @Override
protected boolean shouldNotFilter(HttpServletRequest request) { protected boolean shouldNotFilter(HttpServletRequest request) {
return !request.getRequestURI().startsWith("/api/open/"); String uri = request.getRequestURI();
return uri == null || !uri.contains("/api/open/");
} }
@Override @Override

View File

@@ -9,8 +9,8 @@ export interface TenantRuntimeConfig {
// develop 环境允许本地联调trial/release 请替换为已备案且已配置到小程序后台“服务器域名”的 HTTPS 域名。 // develop 环境允许本地联调trial/release 请替换为已备案且已配置到小程序后台“服务器域名”的 HTTPS 域名。
export const tenantRuntimeConfig: TenantRuntimeConfig = { export const tenantRuntimeConfig: TenantRuntimeConfig = {
apiBaseUrlByEnv: { apiBaseUrlByEnv: {
develop: 'http://127.0.0.1:8112', develop: 'https://easyflowtech.cn/card',
trial: 'https://trial-api.example.com', trial: 'https://easyflowtech.cn/card',
release: 'https://api.example.com', release: 'https://easyflowtech.cn/card',
}, },
}; };