当前位置: 首页 > news >正文

菜单网站图片素材wordpress中英文标题

菜单网站图片素材,wordpress中英文标题,代码错误网站,网站商城怎么做api key认证 api key是一种用户认证的标识符,用户访问api时携带key来认证身份,api key一般是长期可用的 api key需要保证唯一性,随机性.唯一性是因为要和用户对应,随机性是为了避免被暴力猜测出来. 实现: 一般需要在数据库维护记录api key,并记录和用户,权限的关系. 需要提供重…

api key认证

api key是一种用户认证的标识符,用户访问api时携带key来认证身份,api key一般是长期可用的
api key需要保证唯一性,随机性.唯一性是因为要和用户对应,随机性是为了避免被暴力猜测出来.

实现:
一般需要在数据库维护记录api key,并记录和用户,权限的关系.
需要提供重置api key,验证 key的接口.

api key微服务流转

由于项目是微服务项目,所以key传递到mcp服务后,mcp调用其他微服务也需要携带.一般情况,我们可以使用线程变量保存到每个线程,但是mcp sdk在调用tool时创建了新线程,需要我们手动维护sessionId和key的映射关系,通过sessionId传递正确的key到下游服务.

记录sessionId和key:

    @Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {response.setContentType("text/event-stream; charset=utf-8");HttpServletRequest httpRequest = (HttpServletRequest) request;//存储sessionId和key映射。并传递sessionId到tool调用线程。String sessionId = httpRequest.getParameter(SESSION_ID_PARAM);String key = httpRequest.getHeader(KEY_HEADER);if (sessionId != null && key != null) {SessionKeyMap.setKey(sessionId, key);log.debug("Set key for sessionId: {}", sessionId);HttpServletRequest wrappedRequest = new BodyRequestWrapper(httpRequest, sessionId);httpRequest = wrappedRequest;}String uri = httpRequest.getRequestURI();if (!uri.equals("/sse")) {chain.doFilter(httpRequest, response);return;}//处理sse响应,追加key后缀参数。HttpServletResponse httpRes = (HttpServletResponse)response;PrintWriter sseWriter = new SSEWriter(httpRes.getWriter(), key);HttpServletResponseWrapper sseResponse = new HttpServletResponseWrapper(httpRes) {@Overridepublic PrintWriter getWriter() {return sseWriter;}};chain.doFilter(httpRequest, sseResponse);}

BodyRequestWrapper


/*** @author twei*/
public class BodyRequestWrapper extends HttpServletRequestWrapper {private final byte[] body;public BodyRequestWrapper(HttpServletRequest request, String mcpSessionId) throws IOException {super(request);// 1. 获取原始bodyString oldBody = request.getReader().lines().reduce("", (accumulator, actual) -> accumulator + actual);// 2. 解析为MapObjectMapper mapper = new ObjectMapper();Map<String, Object> jsonMap;if (oldBody != null && !oldBody.isEmpty()) {jsonMap = mapper.readValue(oldBody, Map.class);} else {jsonMap = new java.util.HashMap<>();}// ======= 关键逻辑移到这里,跳过initialize =======Object methodObj = jsonMap.get("method");if (methodObj instanceof String && !((String) methodObj).equals("tools/call")) {// 如果包含 initialize,则直接保留原 body,不处理 paramsthis.body = oldBody.getBytes(StandardCharsets.UTF_8);return;}// 重点:把 mcpSessionId 放到 params 里Object paramsObj = jsonMap.get("params");if (paramsObj instanceof Map) {Map<String, Object> paramsMap = (Map<String, Object>) paramsObj;Object argumentsObj = paramsMap.get("arguments");if (argumentsObj instanceof Map) {((Map<String, Object>) argumentsObj).put("mcpSessionId", mcpSessionId);}}// 4. 重新序列化String newBody = mapper.writeValueAsString(jsonMap);body = newBody.getBytes(StandardCharsets.UTF_8);}@Overridepublic ServletInputStream getInputStream() {ByteArrayInputStream bais = new ByteArrayInputStream(body);return new ServletInputStream() {@Override public boolean isFinished() { return bais.available() == 0; }@Override public boolean isReady() { return true; }@Override public void setReadListener(ReadListener listener) {}@Override public int read() { return bais.read(); }};}@Overridepublic BufferedReader getReader() {return new BufferedReader(new InputStreamReader(getInputStream()));}
}

进入tool执行线程后,设置到线程变量MDC中.

  private void registerTool(McpSyncServer mcpSyncServer, Object bean, Method method, McpTool annotation) {String toolName = method.getName();String description = annotation.value().isEmpty() ? extractMethodDescription(method) : annotation.value();String jsonSchema = generateInputSchema(method);McpSchema.Tool tool = new McpSchema.Tool.Builder().name(toolName).description(description).inputSchema(jsonSchema).build();BiFunction<McpSyncServerExchange, Map<String, Object>, McpSchema.CallToolResult> call = (exchange,arguments) -> {try {String mcpSessionId = (String) arguments.get("mcpSessionId");MDC.put("McpSessionId",mcpSessionId);log.info("call " + bean + " " + method);// Convert arguments to match method parameter typesObject[] params = new Object[method.getParameterCount()];Parameter[] parameters = method.getParameters();for (int i = 0; i < parameters.length; i++) {String paramName = parameters[i].getName();Class<?> paramType = parameters[i].getType();Object argValue = arguments.get(paramName);if (argValue != null) {if (paramType == String.class) {params[i] = argValue.toString();} else if (paramType == Integer.class || paramType == int.class) {params[i] = Integer.parseInt(argValue.toString());} else if (paramType == Long.class || paramType == long.class) {params[i] = Long.parseLong(argValue.toString());} else if (paramType == Double.class || paramType == double.class) {params[i] = Double.parseDouble(argValue.toString());} else if (paramType == Boolean.class || paramType == boolean.class) {params[i] = Boolean.parseBoolean(argValue.toString());} else if (paramType == LocalDate.class) {params[i] = LocalDate.parse(argValue.toString());} else if (paramType == LocalDateTime.class) {params[i] = LocalDateTime.parse(argValue.toString());} else {throw new IllegalArgumentException("不支持的mcptool参数类型,只支持基础类型。【" + paramType.getSimpleName() + "】");}}}// 检查必填参数StringBuilder missingFields = new StringBuilder();for (int i = 0; i < parameters.length; i++) {Required required = parameters[i].getAnnotation(Required.class);if (required != null && params[i] == null) {if (missingFields.length() > 0) {missingFields.append(", ");}missingFields.append(parameters[i].getName());}}if (missingFields.length() > 0) {return new McpSchema.CallToolResult(missingFields.toString() + "为必填字段", false);}Object result = method.invoke(bean, params);log.info("call " + bean + " " + method + " " + params + " result: " + result);return new McpSchema.CallToolResult(result.toString(), false);} catch (Exception e) {return new McpSchema.CallToolResult(e.getMessage(), true);}};mcpSyncServer.addTool(new McpServerFeatures.SyncToolSpecification(tool, call));}

向下游发送feign请求时,获取线程变量中的sessionId映射得到key,并在请求头携带key

public class FeignInterceptorConfiguration implements RequestInterceptor {public RequestInterceptor requestInterceptor() {if ("mcp".equals(this.applicationName)) {traceId = MDC.get("McpSessionId");if (traceId != null) {String key = SessionKeyMap.getKey(traceId);if (key != null) {requestTemplate.header("Key", key);}}}}
}

mcp sdk兼容api key

兼容key使用见上文的fdoFilter,在访问sse接口时,向url末尾追加key信息.从而让client访问/mcp/message时能通过认证.

mcp java sdk

HttpServletSseServerTransportProvider是sdk中处理请求的核心类,doGet处理sso等方法,doPost会处理/mcp/message等方法.sendEvent用于发送一个sse事件.sessionFactory用于管理每个session.

@WebServlet(asyncSupported = true)
public class HttpServletSseServerTransportProvider extends HttpServlet implements McpServerTransportProvider
http://www.dtcms.com/a/502188.html

相关文章:

  • 网站建设视频vs技术支持 贵阳贵阳网站建设
  • 厦门建设集团网站怎样买空间做网站
  • 九州娱乐官方网站怎么做代理青海wap网站建设哪家好
  • APP开发网站建设哪家好制作一个网站平台要多钱
  • 广州网站建设公司排行网站后台管理水印怎么做
  • seo建站是什么意思软件系统开发在哪儿
  • 新手网站建设wordpress文章摘要显示
  • 建设网站要花多少钱镇江搜索优化技巧
  • 网站开发客户郑州网站建设推广有限公司
  • 广州市工商注册查询系统唐山网站关键词优化
  • 免费做网站可以一直用吗天津国际工程建设监理公司网站
  • 农业企业网站建设流程建设视频网站
  • 在网站上显示备案信息我的世界做圆网站
  • 如何删除网站的信息吗做任务推广网站
  • 备案审核网站显示500网站开发颜色选择器
  • 贵阳专业做网站的公司班级网站怎么做ppt模板
  • 西宁网站建设哪家强企业网站建设需要许可证吗
  • 营业执照申请网站北京网站搭建报价
  • 哈尔滨优质官网建站企业外贸网站交易平台
  • 唐山丰南建设局网站培训营销型网站建设
  • 企业网站后台内容如何修改网页编辑器安卓
  • 南昌制作网站软件工程建设网最新信息网站
  • 比较好的网页网站设计企业设计网站公司排行榜
  • 东莞排名seo网站关键词优化山东省住房城乡建设部网站首页
  • 免费网站建站w汕头 网站建设
  • 久商推网站建设广西医科大学网站建设
  • 网站模板交易网上推广什么比较赚钱
  • 免费做网站页头图龙华网站建设专业定制企业
  • 顺义做网站同学河北手机网站制作公司
  • 青岛网站推广途径外贸业务怎么利用网站开发客户