package com.wok.supportbot.controller; import com.wok.supportbot.entity.ApiKey; import com.wok.supportbot.entity.SysUser; import com.wok.supportbot.service.ApiKeyService; import com.wok.supportbot.service.SysUserService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Objects; /** * API Key 管理接口 * 提供 API Key 的创建、吊销、启用、删除、分页查询、角色绑定等操作。 */ @Slf4j @RestController @RequestMapping("/api-key") public class ApiKeyController { @Autowired private ApiKeyService apiKeyService; @Autowired private SysUserService sysUserService; /** * 分页查询 API Key 列表 */ @GetMapping("/list") @PreAuthorize("hasRole('admin')") public ResponseEntity> list( @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "20") int size) { try { Map result = apiKeyService.listKeys(page, size); Map data = new java.util.HashMap<>(); data.put("success", true); data.put("data", result.get("records")); data.put("total", result.get("total")); data.put("page", result.get("page")); data.put("size", result.get("size")); data.put("pages", result.get("pages")); return ResponseEntity.ok(data); } catch (Exception e) { log.error("查询 API Key 列表失败", e); return ResponseEntity.status(500).body(Map.of( "success", false, "message", "查询失败:" + e.getMessage() )); } } /** * 创建 API Key * * @param body 请求体,包含 name, description, rateLimit, maxCalls, expireTime, roleIds(可选) */ @PostMapping @PreAuthorize("hasRole('admin')") public ResponseEntity> create(@RequestBody Map body) { try { String name = (String) body.get("name"); if (name == null || name.isBlank()) { return ResponseEntity.badRequest().body(Map.of( "success", false, "message", "名称不能为空" )); } String description = (String) body.getOrDefault("description", ""); Integer rateLimit = body.containsKey("rateLimit") && body.get("rateLimit") != null ? ((Number) body.get("rateLimit")).intValue() : null; Long maxCalls = body.containsKey("maxCalls") && body.get("maxCalls") != null ? ((Number) body.get("maxCalls")).longValue() : null; Date expireTime = null; if (body.get("expireTime") != null) { if (body.get("expireTime") instanceof Number num) { expireTime = new Date(num.longValue()); } else if (body.get("expireTime") instanceof String str && !str.isBlank()) { expireTime = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm").parse(str); } } // 从 SecurityContext 获取当前登录用户 ID Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth == null || !auth.isAuthenticated() || "anonymousUser".equals(auth.getPrincipal())) { return ResponseEntity.status(401).body(Map.of( "success", false, "message", "未登录,无法创建 API Key" )); } SysUser currentUser = sysUserService.getUserByUsername(auth.getName()); Long userId = (currentUser != null) ? currentUser.getId() : null; ApiKey apiKey = apiKeyService.generateKey(userId, name, description, rateLimit, maxCalls, expireTime); // 绑定角色(可选) if (body.containsKey("roleIds")) { List roleIds = parseRoleIds(body.get("roleIds")); apiKeyService.updateKeyRoles(apiKey.getId(), roleIds); } return ResponseEntity.ok(Map.of( "success", true, "message", "创建成功", "data", apiKey )); } catch (IllegalArgumentException e) { return ResponseEntity.badRequest().body(Map.of( "success", false, "message", e.getMessage() )); } catch (Exception e) { log.error("创建 API Key 失败", e); return ResponseEntity.status(500).body(Map.of( "success", false, "message", "创建失败:" + e.getMessage() )); } } /** * 吊销 API Key */ @PutMapping("/{id}/revoke") @PreAuthorize("hasRole('admin')") public ResponseEntity> revoke(@PathVariable Long id) { try { apiKeyService.revokeKey(id); return ResponseEntity.ok(Map.of( "success", true, "message", "已吊销" )); } catch (IllegalArgumentException e) { return ResponseEntity.badRequest().body(Map.of( "success", false, "message", e.getMessage() )); } catch (Exception e) { log.error("吊销 API Key 失败", e); return ResponseEntity.status(500).body(Map.of( "success", false, "message", "吊销失败:" + e.getMessage() )); } } /** * 启用 API Key */ @PutMapping("/{id}/enable") @PreAuthorize("hasRole('admin')") public ResponseEntity> enable(@PathVariable Long id) { try { apiKeyService.enableKey(id); return ResponseEntity.ok(Map.of( "success", true, "message", "已启用" )); } catch (IllegalArgumentException e) { return ResponseEntity.badRequest().body(Map.of( "success", false, "message", e.getMessage() )); } catch (Exception e) { log.error("启用 API Key 失败", e); return ResponseEntity.status(500).body(Map.of( "success", false, "message", "启用失败:" + e.getMessage() )); } } /** * 删除 API Key */ @DeleteMapping("/{id}") @PreAuthorize("hasRole('admin')") public ResponseEntity> delete(@PathVariable Long id) { try { apiKeyService.deleteKey(id); return ResponseEntity.ok(Map.of( "success", true, "message", "删除成功" )); } catch (IllegalArgumentException e) { return ResponseEntity.badRequest().body(Map.of( "success", false, "message", e.getMessage() )); } catch (Exception e) { log.error("删除 API Key 失败", e); return ResponseEntity.status(500).body(Map.of( "success", false, "message", "删除失败:" + e.getMessage() )); } } /** * 更新 API Key 绑定的客服角色 * 空数组表示不限制(返回所有启用角色) */ @PutMapping("/{id}/roles") @PreAuthorize("hasRole('admin')") public ResponseEntity> updateRoles( @PathVariable Long id, @RequestBody Map body) { try { List roleIds = parseRoleIds(body.get("roleIds")); apiKeyService.updateKeyRoles(id, roleIds); return ResponseEntity.ok(Map.of( "success", true, "message", "角色绑定更新成功" )); } catch (IllegalArgumentException e) { return ResponseEntity.badRequest().body(Map.of( "success", false, "message", e.getMessage() )); } catch (Exception e) { log.error("更新 API Key 角色绑定失败", e); return ResponseEntity.status(500).body(Map.of( "success", false, "message", "更新失败:" + e.getMessage() )); } } /** * 解析请求体中的 roleIds 列表 */ @SuppressWarnings("unchecked") private List parseRoleIds(Object raw) { if (!(raw instanceof List list)) { return List.of(); } return list.stream() .filter(Objects::nonNull) .map(item -> item instanceof Number n ? n.longValue() : Long.parseLong(item.toString())) .filter(id -> id > 0) .distinct() .toList(); } }