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

网站研发费用吗公司的网站怎么运营

网站研发费用吗,公司的网站怎么运营,昆明网站建设yn119,深圳市保障房申请网站场景 用户无需登录#xff0c;仅仅根据给定的访问keyId和keySecret就可以访问接口。 keyId 等可以明文发送#xff08;不涉及机密#xff09;#xff0c;后端直接从请求头读取。keySecret 不可明文#xff0c;需要加密后放在另一个请求头#xff08;或请求体#xff0…场景 用户无需登录仅仅根据给定的访问keyId和keySecret就可以访问接口。 keyId 等可以明文发送不涉及机密后端直接从请求头读取。keySecret 不可明文需要加密后放在另一个请求头或请求体里比如 Encrypted-Data。timestamp 6位随机值(nonce) 用来防重放或检验请求时效需要在明文里也传递给后端以方便后端做校验。后端拿到 Encrypted-Data 后使用私钥解密得到真正的 keySecret、然后再和明文传递过来的 timestamp、randomValue 做进一步匹配。 # 请求头中的信息 keyId timestamp randomValue Encrypted-Data{\keySecret\:\%s\,\timestamp\:\%s\,\randomValue\:\%s\}客户端 前端调用拼装并加密数据 假设我们有如下信息 keyId“myKeyId”keySecret“myKeySecret”需加密timestamp“20251225103449”格式 yyyyMMddHHmmssrandomValue6 位随机数如 “538201” 生成随机数 时间戳 function generateTimestamp() {// 生成形如 20251225103449 的日期字符串 (yyyyMMddHHmmss)const now new Date();const yyyy now.getFullYear();const MM String(now.getMonth() 1).padStart(2, 0);const dd String(now.getDate()).padStart(2, 0);const HH String(now.getHours()).padStart(2, 0);const mm String(now.getMinutes()).padStart(2, 0);const ss String(now.getSeconds()).padStart(2, 0);return ${yyyy}${MM}${dd}${HH}${mm}${ss}; }function generateRandomValue6() {// 生成 6 位随机数return String(Math.floor(Math.random() * 1000000)).padStart(6, 0); } 加密 keySecret 假设使用 jsencrypt 进行 RSA 加密并把 keySecret timestamp randomValue 打包在一个 JSON 对象里加密。 import axios from axios; import JSEncrypt from jsencrypt;// RSA 公钥 const PUBLIC_KEY_PEM -----BEGIN PUBLIC KEY----- MIIBIjANBgkqh... -----END PUBLIC KEY----- ;// 拼装并加密 function encryptKeyInfo(keySecret, timestamp, randomValue) {const payload {keySecret,timestamp,randomValue};const jsonStr JSON.stringify(payload);const jsEncrypt new JSEncrypt();jsEncrypt.setPublicKey(PUBLIC_KEY_PEM);const encrypted jsEncrypt.encrypt(jsonStr);if (!encrypted) {throw new Error(加密失败请检查公钥格式或数据大小);}return encrypted; // Base64 编码的加密结果 }// 发送请求示例 async function callSecureApi() {const keyId myKeyId;const timestamp generateTimestamp(); const randomValue generateRandomValue6(); const keySecret myKeySecret; // 需要加密的机密// 把 keySecret、timestamp、randomValue 一并加密const encryptedData encryptKeyInfo(keySecret, timestamp, randomValue);// 发请求时除了 Encrypted-Data 外把 keyId/timestamp/randomValue 也都明文放在 header// 这样后端可做交叉验证try {const resp await axios.post(/api/secure,{}, // body 可为空或随意{headers: {keyId: keyId,timestamp: timestamp,randomValue: randomValue,Encrypted-Data: encryptedData}});console.log(后端返回:, resp.data);} catch (e) {console.error(e);} }Java调用 maven依赖 dependencygroupIdorg.apache.httpcomponents/groupIdartifactIdhttpclient/artifactIdversion4.5.14/version /dependency代码调用 package com.demo.test;import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils;import javax.crypto.Cipher; import java.io.IOException; import java.security.KeyFactory; import java.security.PublicKey; import java.security.spec.X509EncodedKeySpec; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Base64; import java.util.Random;public class ThirdPartyCaller {// 假设你目标服务的地址private static final String BASE_URL http://localhost:13131;// 例如 http://localhost:8080 或生产环境 https://yourdomain.compublic static void main(String[] args) {try {// 1) 先获取公钥(PEM 格式)String publicKeyPem -----BEGIN PUBLIC KEY-----\n MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs3ZYer3Ibej9o4IRlzkC\n 2Hjk0roGuR4ckIafh/DZNHv/JfHgM7R10BLfTnkiGyrps7Lk36Gm9RnafduphCMX\n nG7nZdCYKt16aE4Tqb7FZ/pLz8WOjpxiSLA361wknG9UCyytmhXjo6wZ8zxNoSd\n ePhMkGBVxwCbeZS9wldBbwpRpMY1Dsyve7C8COhEiWIFXz0ruMsskukCue2Q6nNh\n 6dLIN17MtEqa7in7Q6xPvyNPsCkfI8PAvQqGO5thdZoTcT7XPHrBJesfuS8sSmtF\n xMPfI/Nke/KTykeDcf4PHKd0GP5c6/p0XVkzxHm7sbFEEdII41e1Gd81gJ6bPQc\n dQIDAQAB\n -----END PUBLIC KEY-----;// 2) 解析 PEM 得到 PublicKey 对象PublicKey pubKey parsePublicKeyFromPem(publicKeyPem);// 3) 准备要加密和要发送的字段String keyId qwertyuiopasdfghjklzxcvbnm;String keySecret demo123!;String timestamp generateTimestamp(); // yyyyMMddHHmmssString randomValue generateRandomValue6(); // 6位随机数// 4) 组装 JSON再用公钥 RSA 加密// 若与前端示例一致可把 (keySecret, timestamp, randomValue) 放到 JSONString payloadJson String.format({\keySecret\:\%s\,\timestamp\:\%s\,\randomValue\:\%s\},keySecret, timestamp, randomValue);String encryptedData rsaEncrypt(pubKey, payloadJson);// 5) 调用 /api/secure 接口String result callSecureApi(keyId, timestamp, randomValue, encryptedData);System.out.println(调用 /aliyun_sms/send 响应: result);} catch (Exception e) {e.printStackTrace();}}/*** 第一步解析 PEM 格式的公钥字符串得到 PublicKey 对象* 如果服务器只返回纯Base64(无头尾)可根据实际情况调整。*/private static PublicKey parsePublicKeyFromPem(String publicKeyPem) throws Exception {// 移除头尾行和换行保留中间的Base64部分String base64 publicKeyPem.replaceAll(-----BEGIN PUBLIC KEY-----, ).replaceAll(-----END PUBLIC KEY-----, ).replaceAll(\\s, );byte[] decoded Base64.getDecoder().decode(base64);X509EncodedKeySpec keySpec new X509EncodedKeySpec(decoded);KeyFactory keyFactory KeyFactory.getInstance(RSA);return keyFactory.generatePublic(keySpec);}/*** 第二步把要加密的JSON用RSA公钥加密*/private static String rsaEncrypt(PublicKey publicKey, String data) throws Exception {Cipher cipher Cipher.getInstance(RSA/ECB/PKCS1Padding);cipher.init(Cipher.ENCRYPT_MODE, publicKey);byte[] encrypted cipher.doFinal(data.getBytes());return Base64.getEncoder().encodeToString(encrypted);}/*** 生成时间戳 (yyyyMMddHHmmss)*/private static String generateTimestamp() {DateTimeFormatter fmt DateTimeFormatter.ofPattern(yyyyMMddHHmmss);return LocalDateTime.now().format(fmt);}/*** 生成6位随机数 (000000~999999)*/private static String generateRandomValue6() {Random random new Random();int num random.nextInt(1_000_000);return String.format(%06d, num);}/*** 第三步调用 /api/secure 接口并在header中带上 keyId, timestamp, randomValue, Encrypted-Data*/private static String callSecureApi(String keyId, String timestamp,String randomValue, String encryptedData) throws IOException {String url BASE_URL /aliyun_sms/send;try (CloseableHttpClient httpClient HttpClients.createDefault()) {HttpPost post new HttpPost(url);// 设置headerpost.setHeader(keyId, keyId);post.setHeader(timestamp, timestamp);post.setHeader(randomValue, randomValue);post.setHeader(Encrypted-Data, encryptedData);post.setHeader(Content-Type, application/json;charsetUTF-8);// 此示例没给 body若需要可在 body 放更多数据//post.setEntity(new StringEntity({\name\:\张三\}, UTF-8));try (CloseableHttpResponse response httpClient.execute(post)) {int statusCode response.getStatusLine().getStatusCode();String respBody EntityUtils.toString(response.getEntity(), UTF-8);if (statusCode 200) {return respBody;} else {throw new IOException(调用 /api/secure 失败, HTTP状态 statusCode , body respBody);}}}} }服务端 RSA私钥解密 package com.demo.lcpd.utils;import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component;import javax.crypto.Cipher; import java.nio.charset.StandardCharsets; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.spec.PKCS8EncodedKeySpec; import java.util.Base64;Component public class RsaDecryptor {Value(${security.rsa.privateKeyPem})private String privateKeyPem;public String decrypt(String encryptedBase64) throws Exception {// 1) 去掉 PEM 格式里的头尾和换行只保留真正的Base64部分String base64Key removePemFormatting(privateKeyPem);// 2) 把Base64解码还原成私钥对象byte[] keyBytes Base64.getDecoder().decode(base64Key);PKCS8EncodedKeySpec keySpec new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory KeyFactory.getInstance(RSA);PrivateKey privateKey keyFactory.generatePrivate(keySpec);// 3) 解密byte[] encryptedBytes Base64.getDecoder().decode(encryptedBase64);Cipher cipher Cipher.getInstance(RSA/ECB/PKCS1Padding);cipher.init(Cipher.DECRYPT_MODE, privateKey);byte[] decrypted cipher.doFinal(encryptedBytes);return new String(decrypted, StandardCharsets.UTF_8);}private String removePemFormatting(String pem) {// 移除行首行尾 (-----BEGIN PRIVATE KEY----- / -----END PRIVATE KEY-----) 以及换行return pem.replaceAll(-----BEGIN PRIVATE KEY-----, ).replaceAll(-----END PRIVATE KEY-----, ).replaceAll(\\s, );}} 自定义拦截器 package com.demo.lcpd.intercept;import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.demo.lcpd.utils.RsaDecryptor; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor;import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.HashMap; import java.util.Map;Component public class RsaAuthInterceptor implements HandlerInterceptor {Resourceprivate RsaDecryptor rsaDecryptor;private MapString, String keyStore new HashMap();//添加允许通过的keyId和keySecretpublic RsaAuthInterceptor() {keyStore.put(qwertyuiopasdfghjklzxcvbnm, demo123!);}Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String keyId request.getHeader(keyId);String timestamp request.getHeader(timestamp);String randomValue request.getHeader(randomValue);String encryptedData request.getHeader(Encrypted-Data);if (keyId null || timestamp null || randomValue null || encryptedData null) {response.sendError(HttpServletResponse.SC_UNAUTHORIZED, Missing auth headers);return false;}try {// 2) RSA 私钥解密String decryptedJson rsaDecryptor.decrypt(encryptedData);// decryptedJson 形如: {keySecret:myKeySecret,timestamp:20251225103449,randomValue:538201}// 3) 解析 JSONObjectMapper objectMapper new ObjectMapper();JsonNode node objectMapper.readTree(decryptedJson);String decryptedKeySecret node.get(keySecret).asText();String decryptedTimestamp node.get(timestamp).asText();String decryptedRandomValue node.get(randomValue).asText();// 4) 与明文传递的 timestamp、randomValue 对比if (!timestamp.equals(decryptedTimestamp) || !randomValue.equals(decryptedRandomValue)) {response.sendError(HttpServletResponse.SC_UNAUTHORIZED, Timestamp or randomValue mismatch);return false;}// 5) 校验 keyId 是否存在以及 keySecret 是否匹配if (!keyStore.containsKey(keyId)) {response.sendError(HttpServletResponse.SC_UNAUTHORIZED, Invalid keyId);return false;}String expectedSecret keyStore.get(keyId);if (!expectedSecret.equals(decryptedKeySecret)) {response.sendError(HttpServletResponse.SC_UNAUTHORIZED, Invalid keySecret);return false;}// 6) 校验 timestamp 是否在合理范围 (例如 ±15分钟)if (!checkTimestampValid(timestamp)) {response.sendError(HttpServletResponse.SC_UNAUTHORIZED, Timestamp expired or invalid);return false;}// 7) 防重放检查 (keyId timestamp randomValue) 是否已使用过// 这里仅示例不做具体实现// boolean notUsed checkAndMarkUsed(keyId, timestamp, randomValue);// if (!notUsed) {// response.sendError(HttpServletResponse.SC_UNAUTHORIZED, Replay attack detected);// return;// }// 校验成功return true;} catch (Exception e) {response.sendError(HttpServletResponse.SC_UNAUTHORIZED, Decryption or parse error);return false;}}private boolean checkTimestampValid(String timestampStr) {try {// 解析 yyyyMMddHHmmssDateTimeFormatter fmt DateTimeFormatter.ofPattern(yyyyMMddHHmmss);LocalDateTime reqTime LocalDateTime.parse(timestampStr, fmt);LocalDateTime now LocalDateTime.now();// 假设 15 分钟有效期return !reqTime.isBefore(now.minusMinutes(15)) !reqTime.isAfter(now.plusMinutes(15));} catch (Exception e) {return false;}} } 注册拦截器 package com.demo.lcpd.conf;import com.demo.lcpd.intercept.RsaAuthInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import javax.annotation.Resource;Configuration public class WebMvcConfig implements WebMvcConfigurer {Resourceprivate RsaAuthInterceptor rsaAuthInterceptor;Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(rsaAuthInterceptor).addPathPatterns(/**);} }在 Java 中生成 RSA 公私钥 使用 KeyPairGenerator public class RsaKeyGeneratorPemExample {public static void main(String[] args) throws Exception {KeyPairGenerator keyPairGenerator KeyPairGenerator.getInstance(RSA);keyPairGenerator.initialize(2048);KeyPair keyPair keyPairGenerator.generateKeyPair();// Base64String publicKeyBase64 Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());String privateKeyBase64 Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());// 包装成 PEMString publicKeyPem convertToPem(publicKeyBase64, true);String privateKeyPem convertToPem(privateKeyBase64, false);System.out.println(publicKeyPem);System.out.println(privateKeyPem);}private static String convertToPem(String base64Key, boolean isPublic) {int lineLength 64;StringBuilder sb new StringBuilder();if (isPublic) {sb.append(-----BEGIN PUBLIC KEY-----\n);} else {sb.append(-----BEGIN PRIVATE KEY-----\n);}for (int i 0; i base64Key.length(); i lineLength) {int end Math.min(i lineLength, base64Key.length());sb.append(base64Key, i, end).append(\n);}if (isPublic) {sb.append(-----END PUBLIC KEY-----\n);} else {sb.append(-----END PRIVATE KEY-----\n);}return sb.toString();}}运行后就能得到标准的 PEM 形式公私钥类似 -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFA... ...LQIDAQAB -----END PUBLIC KEY----------BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQ... ...2ww -----END PRIVATE KEY-----这两个就是 PEM 格式的“公钥”和“私钥”。 前端使用的 PUBLIC_KEY_PEM 是什么 可以是带头尾的 PEM 在前端例如使用 jsencrypt时最常见的做法就是直接使用 PEM 格式 const PUBLIC_KEY_PEM -----BEGIN PUBLIC KEY----- MIIBIjANBgkqh... -----END PUBLIC KEY-----; 然后在加密时像这样写 import JSEncrypt from jsencrypt;const jsEncrypt new JSEncrypt(); // 直接 set PEM 格式的字符串即可 jsEncrypt.setPublicKey(PUBLIC_KEY_PEM); const encrypted jsEncrypt.encrypt(hello world);jsencrypt 这个库支持 PEM 格式字符串包含头尾。也就是说如果你在 Java 端生成了 PEM直接整段复制到前端就行。 也可以是纯 Base64 字符串 有些前端库也允许你只传Base64 编码的公钥而不含头尾。那你就可以给它传 // 纯 Base64不带 -----BEGIN---- const PUBLIC_KEY_BASE64 MIIBIjANBgkq…;const jsEncrypt new JSEncrypt(); jsEncrypt.setPublicKey(-----BEGIN PUBLIC KEY----- ${PUBLIC_KEY_BASE64} -----END PUBLIC KEY-----);要点总结 1.后端生成 RSA 公私钥 公钥用来给前端加密私钥留在后端解密不要泄露。 2.前端使用 jsencrypt PEM 格式带 -----BEGIN PUBLIC KEY-----的公钥即可把要加密的字段 (keySecret, timestamp, randomValue) JSON 化 - 调用 .encrypt(…) - 得到密文(Base64)。 3.后端使用私钥解密 先去掉 PEM 的头尾只保留 Base64 - 解码 - Cipher.getInstance(“RSA/ECB/PKCS1Padding”) 解密拿到明文 JSON解析出 keySecret, timestamp, randomValue与前端同时传来的明文 timestamp, randomValue 做比对再检查 keyId 对应的 keySecret 是否匹配。 4.时间戳 随机值 可做防重放时间戳超时或重复使用同一 (keyId timestamp randomValue)则拒绝请求。 5.配合 HTTPS RSA 加密可以避免明文 keySecret 出现在网络上但最佳实践还是要用 HTTPS防止更多层面的攻击、劫持、篡改。
http://www.hkea.cn/news/14513498/

相关文章:

  • 四川省建设工程招投标网站小网站做长尾词还是流量词
  • 重庆属于哪个省china东莞seo
  • 电子商务和网站建设方案wordpress超级留言版
  • 双牌网站建设网站开发工程师岗位说明书
  • 金融理财网站建设科技小制作 手工 简单
  • 专业的网站建设宝安西乡如何制作app软件步骤
  • 电子商务网站建设各项费用预算是多少烟台网站建设技术托管
  • 网站续费模版网站建设的售后服务
  • 地方志网站建设甘肃网站备案审核
  • 做汽车价格的网站wordpress 新浪微博
  • saas建站 cms单县住房和城乡建设局网站
  • 个人网站作品下载网站建设与网页设计大作业
  • 郑州汽车网站建设哪家好最新军事新闻报道
  • 网站建设与管理试题及答案芜湖龙湖建设工程有限公司网站
  • 网站制作公司服务东莞怎样做网站建设
  • 企石网站建设注册公司的流程图
  • 腾讯理财是什么样的做网站江门网站建设设计
  • 企业培训师资格证网络优化主要做什么
  • aap手机网站建设个人微博网页制作代码教程
  • 陕西十二建设有限公司网站怎么制作网站教程步骤视频
  • 有没有做皮艺的网站预算有哪些网站做私活
  • 做好网站功能性建设工作微商网站如何做推广方案
  • 做网站的出路wordpress 动作钩子
  • 2003建网站做网站软件j
  • 国外代理网站外贸推广引流系统
  • 沧州网站建设代理价格wordpress网站加速
  • 网站模板html 汽车膜wordpress 文章长度
  • 产品网站怎么做网络广告的特点是
  • 顺义网站做的比较好的公司网站初期建设的成本来源
  • 北京网站建设公司拟网站建设怎么配置伪静态文件