Spring设计安全的Restful接口-无用户状态的安全

来源:互联网 发布:国企下岗知乎 编辑:程序博客网 时间:2024/05/22 00:07

设计安全的Restful接口:无用户交互状态的接口安全设计。我们需要实现UR拦截请求拦截,接口接入授权验证和请求验重。本文中不涉及任何用户校验。

设计原理

1.UR拦截请求拦截:通过URL进行拦截过滤;

2.接入授权验证:验证请求头Token;

3.请求验重:验证请求序列Sequence;

接口设计文档请参考:WMS系统对外开放接口设计文档-V.1.0.docx

注:文档禁用于商业用途!

安全过滤器

package com.wlyd.fmcgwms.util.security;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.alibaba.fastjson.JSONObject;import com.wlyd.fmcgwms.util.Log;import com.wlyd.fmcgwms.util.SAASTokenManager;import com.wlyd.fmcgwms.util.StaticProperty;import com.wlyd.fmcgwms.util.api.RSAUtils;import com.wlyd.fmcgwms.util.ehcache.EhcacheUtil;import com.wlyd.fmcgwms.util.sysinit.InitSysProperties;/** * 接口安全过滤器 *  * @package com.wlyd.fmcgwms.util.security.SecurityFilter * @date   2017年3月15日  下午1:57:18 * @author pengjunlin * @comment    * @update */public class SecurityFilter implements Filter {private static String API_ISENABLE ;// WMS是否开通对外接口private static String API_PALTFORM;// WMS开放的平台编码private static String API_MEMBERCODE;//WMS开放的服务商编码private static String publicKey;// 公钥private static String privateKey;// 私钥@Overridepublic void destroy() {// TODO Auto-generated method stub}/** * 验证配置是否规范 *  * @MethodName: isConfiged  * @Description:  * @param platformCode * @param memberCode * @return * @throws */private boolean isConfiged(String platformCode,String memberCode){        if(API_ISENABLE==null||!API_ISENABLE.equals("true")){return false;}        if(API_PALTFORM==null||platformCode==null||!platformCode.equals(API_PALTFORM)){        return false;        }if (API_MEMBERCODE==null||memberCode == null||! memberCode.equals(API_MEMBERCODE)) {return false;}return true;}/** * 验证token是否有效 *  * @MethodName: validateToken  * @Description:  * @param token * @return * @throws */private boolean validateToken(String token){if(token==null||token.equals("")){return false;}String params[]=SAASTokenManager.decryptToken(privateKey, token, "&");if(params==null||params.length<3){return false;}long now=System.currentTimeMillis();// Token超时验证20slong seconds=(now-Long.valueOf(params[2]))/1000;if(!API_PALTFORM.equals(params[0])||!API_MEMBERCODE.equals(params[1])||seconds>20){return false;}return true;}/** * 验证请求是否重复 *  * @MethodName: validateSequece  * @Description:  * @param sequence * @return * @throws */public boolean validateSequece(String sequence){if(sequence==null||sequence.equals("")){return false;}String requestSequence=(String) EhcacheUtil.get(StaticProperty.REQUESTCACHE, sequence);// 请求序列相同验证失败if(requestSequence!=null&&sequence.equals(requestSequence)){return false;}return true;}@Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {PrintWriter out = null;HttpServletRequest req = (HttpServletRequest) request;HttpServletResponse res = (HttpServletResponse) response;String platformCode = req.getHeader("PlatformCode");String memberCode = req.getHeader("MemberCode");String token = req.getHeader("Token");String sequence = req.getHeader("Sequence");//String path = req.getServletPath();try {byte [] bytes=SAASTokenManager.generateBytesToken(publicKey, platformCode, memberCode,"&");token = RSAUtils.bytesToString(bytes);} catch (Exception e1) {e1.printStackTrace();}// 验证接口是否配置正确 if(!isConfiged(platformCode, memberCode)){JSONObject json = new JSONObject();json.put("IsSuccess", "false");json.put("OperationDesc", "API parameters are not configed right! ");json.put("ResultCode", ResultCode.OPEN_API_CONFIG_ERROR);try {out = res.getWriter();out.write(json.toJSONString());} catch (Exception e) {e.printStackTrace();}return;}// 验证Token是否合法if(!validateToken(token)){JSONObject json = new JSONObject();json.put("IsSuccess", "false");json.put("OperationDesc", "Unauthorized:Token is invalid!");json.put("ResultCode", ResultCode.OPEN_API_TOKEN_INVALID);try {out = res.getWriter();out.write(json.toJSONString());} catch (Exception e) {e.printStackTrace();}return;}// 验证Sequence是否合法if(!validateSequece(sequence)){JSONObject json = new JSONObject();json.put("IsSuccess", "false");json.put("OperationDesc", "Refused:request API too frequently!");json.put("ResultCode", ResultCode.OPEN_API_REQUEST_REQUENTLY);try {out = res.getWriter();out.write(json.toJSONString());} catch (Exception e) {e.printStackTrace();}return;}chain.doFilter(request, response);}@Overridepublic void init(FilterConfig arg0) throws ServletException {Log.getLogger(getClass()).info(">>>SecurityFilter invoke init method。。。。。。。。。START!"); API_ISENABLE = InitSysProperties.getLowerCaseFromEhcache(StaticProperty.WMS_OPEN_API_ISENABLE);API_PALTFORM = InitSysProperties.getUpperCaseFromEhcache(StaticProperty.WMS_OPEN_API_PLATFORM);API_MEMBERCODE = InitSysProperties.getUpperCaseFromEhcache(StaticProperty.WMS_OPEN_API_MEMBERCODE);publicKey=EhcacheUtil.get(StaticProperty.WMS_OPEN_API_RSA_PUBLIC_KEY).toString();privateKey=EhcacheUtil.get(StaticProperty.WMS_OPEN_API_RSA_PRIVATE_KEY).toString();Log.getLogger(getClass()).info(">>>SecurityFilter invoke init method。。。。。。。。。SUCCESS!"); }}

注:需要通过RSA工具生成密钥对(公钥&私钥)。

web.xml配置过滤器

<filter><filter-name>SecurityFilter</filter-name><filter-class>com.wlyd.fmcgwms.util.security.SecurityFilter</filter-class></filter><filter-mapping><filter-name>SecurityFilter</filter-name><url-pattern>/openapi/*</url-pattern></filter-mapping>

控制层openapi接口

package com.wlyd.fmcgwms.controller.security;import java.util.HashMap;import java.util.Map;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import com.wlyd.fmcgwms.controller.BaseController;import com.wlyd.fmcgwms.util.Tools;/** * 开放API控制层 *  * @package com.wlyd.fmcgwms.controller.platform.OpenAPIController * @date   2017年3月14日  下午4:52:12 * @author pengjunlin * @comment    * @update */@Controller@RequestMapping("/openapi")public class OpenAPIController extends BaseController{/** * 未授权 *  * @MethodName: unauthenticated  * @Description:  * @return * @throws */@RequestMapping("/unauthenticated")@ResponseBodypublic String unauthenticated(){Map<String,Object> map=new HashMap<String, Object>();map.put("IsSuccess", "false");map.put("OperationDesc", "Unauthenticated:Please contact to WMS developers!");return Tools.toJson(map);}/** * 授权成功 *  * @MethodName: success  * @Description:  * @return * @throws */@RequestMapping("/success")@ResponseBodypublic String success(){Map<String,Object> map=new HashMap<String, Object>();map.put("IsSuccess", "true");map.put("OperationDesc", "Authenticated!");return Tools.toJson(map);}}

没有其它的方法。

RSA加密工具

package com.wlyd.fmcgwms.util.api;import java.io.ByteArrayOutputStream;import java.security.Key;import java.security.KeyFactory;import java.security.KeyPair;import java.security.KeyPairGenerator;import java.security.PrivateKey;import java.security.PublicKey;import java.security.Signature;import java.security.interfaces.RSAPrivateKey;import java.security.interfaces.RSAPublicKey;import java.security.spec.PKCS8EncodedKeySpec;import java.security.spec.X509EncodedKeySpec;import java.util.HashMap;import java.util.Map;import javax.crypto.Cipher;/** * <p> * RSA公钥/私钥/签名工具包 * </p> * <p> * 罗纳德·李维斯特(Ron [R]ivest)、阿迪·萨莫尔(Adi [S]hamir)和伦纳德·阿德曼(Leonard [A]dleman) * </p> * <p> * 字符串格式的密钥在未在特殊说明情况下都为BASE64编码格式<br/> * 由于非对称加密速度极其缓慢,一般文件不使用它来加密而是使用对称加密,<br/> * 非对称加密算法可以用来对对称加密的密钥加密,这样保证密钥的安全也就保证了数据的安全 * </p> *  * @author IceWee * @date 2012-4-26 * @version 1.0 */public class RSAUtils {/** * 加密算法RSA */public static final String KEY_ALGORITHM = "RSA";/** * 签名算法 */public static final String SIGNATURE_ALGORITHM = "MD5withRSA";/** * 获取公钥的key */private static final String PUBLIC_KEY = "RSAPublicKey";/** * 获取私钥的key */private static final String PRIVATE_KEY = "RSAPrivateKey";/** * RSA最大加密明文大小 */private static final int MAX_ENCRYPT_BLOCK = 117;/** * RSA最大解密密文大小 */private static final int MAX_DECRYPT_BLOCK = 128;/** * <p> * 生成密钥对(公钥和私钥) * </p> *  * @return * @throws Exception */public static Map<String, Object> genKeyPair() throws Exception {KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);keyPairGen.initialize(1024);KeyPair keyPair = keyPairGen.generateKeyPair();RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();Map<String, Object> keyMap = new HashMap<String, Object>(2);keyMap.put(PUBLIC_KEY, publicKey);keyMap.put(PRIVATE_KEY, privateKey);return keyMap;}/** * <p> * 用私钥对信息生成数字签名 * </p> *  * @param data *            已加密数据 * @param privateKey *            私钥(BASE64编码) *  * @return * @throws Exception */public static String sign(byte[] data, String privateKey) throws Exception {byte[] keyBytes = Base64Utils.decode(privateKey);PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);signature.initSign(privateK);signature.update(data);return Base64Utils.encode(signature.sign());}/** * <p> * 校验数字签名 * </p> *  * @param data *            已加密数据 * @param publicKey *            公钥(BASE64编码) * @param sign *            数字签名 *  * @return * @throws Exception *  */public static boolean verify(byte[] data, String publicKey, String sign)throws Exception {byte[] keyBytes = Base64Utils.decode(publicKey);X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);PublicKey publicK = keyFactory.generatePublic(keySpec);Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);signature.initVerify(publicK);signature.update(data);return signature.verify(Base64Utils.decode(sign));}/** * <P> * 私钥解密 * </p> *  * @param encryptedData *            已加密数据 * @param privateKey *            私钥(BASE64编码) * @return * @throws Exception */public static byte[] decryptByPrivateKey(byte[] encryptedData,String privateKey) throws Exception {byte[] keyBytes = Base64Utils.decode(privateKey);PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.DECRYPT_MODE, privateK);int inputLen = encryptedData.length;ByteArrayOutputStream out = new ByteArrayOutputStream();int offSet = 0;byte[] cache;int i = 0;// 对数据分段解密while (inputLen - offSet > 0) {if (inputLen - offSet > MAX_DECRYPT_BLOCK) {cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);} else {cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_DECRYPT_BLOCK;}byte[] decryptedData = out.toByteArray();out.close();return decryptedData;}/** * <p> * 公钥解密 * </p> *  * @param encryptedData *            已加密数据 * @param publicKey *            公钥(BASE64编码) * @return * @throws Exception */public static byte[] decryptByPublicKey(byte[] encryptedData,String publicKey) throws Exception {byte[] keyBytes = Base64Utils.decode(publicKey);X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);Key publicK = keyFactory.generatePublic(x509KeySpec);Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.DECRYPT_MODE, publicK);int inputLen = encryptedData.length;ByteArrayOutputStream out = new ByteArrayOutputStream();int offSet = 0;byte[] cache;int i = 0;// 对数据分段解密while (inputLen - offSet > 0) {if (inputLen - offSet > MAX_DECRYPT_BLOCK) {cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);} else {cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_DECRYPT_BLOCK;}byte[] decryptedData = out.toByteArray();out.close();return decryptedData;}/** * <p> * 公钥加密 * </p> *  * @param data *            源数据 * @param publicKey *            公钥(BASE64编码) * @return * @throws Exception */public static byte[] encryptByPublicKey(byte[] data, String publicKey)throws Exception {byte[] keyBytes = Base64Utils.decode(publicKey);X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);Key publicK = keyFactory.generatePublic(x509KeySpec);// 对数据加密Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.ENCRYPT_MODE, publicK);int inputLen = data.length;ByteArrayOutputStream out = new ByteArrayOutputStream();int offSet = 0;byte[] cache;int i = 0;// 对数据分段加密while (inputLen - offSet > 0) {if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);} else {cache = cipher.doFinal(data, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_ENCRYPT_BLOCK;}byte[] encryptedData = out.toByteArray();out.close();return encryptedData;}/** * <p> * 私钥加密 * </p> *  * @param data *            源数据 * @param privateKey *            私钥(BASE64编码) * @return * @throws Exception */public static byte[] encryptByPrivateKey(byte[] data, String privateKey)throws Exception {byte[] keyBytes = Base64Utils.decode(privateKey);PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.ENCRYPT_MODE, privateK);int inputLen = data.length;ByteArrayOutputStream out = new ByteArrayOutputStream();int offSet = 0;byte[] cache;int i = 0;// 对数据分段加密while (inputLen - offSet > 0) {if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);} else {cache = cipher.doFinal(data, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_ENCRYPT_BLOCK;}byte[] encryptedData = out.toByteArray();out.close();return encryptedData;}/** * <p> * 获取私钥 * </p> *  * @param keyMap *            密钥对 * @return * @throws Exception */public static String getPrivateKey(Map<String, Object> keyMap)throws Exception {Key key = (Key) keyMap.get(PRIVATE_KEY);return Base64Utils.encode(key.getEncoded());}/** * <p> * 获取公钥 * </p> *  * @param keyMap *            密钥对 * @return * @throws Exception */public static String getPublicKey(Map<String, Object> keyMap)throws Exception {Key key = (Key) keyMap.get(PUBLIC_KEY);return Base64Utils.encode(key.getEncoded());}/** * 将加密后的字节数组转换为对象 *  * @MethodName: bytesToString  * @Description:  * @param encrytpByte * @return * @throws */public static String bytesToString(byte[] encrytpByte) {     String result = "";     for (Byte bytes : encrytpByte) {         result += bytes.toString() + " ";     }     return result; }/** * 公钥加密 *  * @MethodName: encrypt  * @Description:  * @param publicKey * @param obj * @return * @throws */public static byte[] encrypt(RSAPublicKey publicKey, byte[] obj) {     if (publicKey != null) {         try {             Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);             cipher.init(Cipher.ENCRYPT_MODE, publicKey);             return cipher.doFinal(obj);         } catch (Exception e) {             e.printStackTrace();         }     }     return null; }/** * 私钥加密 *  * @MethodName: decrypt  * @Description:  * @param privateKey * @param obj * @return * @throws */public static byte[] decrypt(RSAPrivateKey privateKey, byte[] obj) {     if (privateKey != null) {         try {             Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);             cipher.init(Cipher.DECRYPT_MODE, privateKey);             return cipher.doFinal(obj);         } catch (Exception e) {             e.printStackTrace();         }     }     return null; }}

Token管理工具

package com.wlyd.fmcgwms.util;import java.sql.Timestamp;import java.util.Date;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;import com.wlyd.fmcgwms.persistence.beans.api.AccessToken;import com.wlyd.fmcgwms.util.api.Base64Utils;import com.wlyd.fmcgwms.util.api.RSAUtils;import com.wlyd.fmcgwms.util.ehcache.EhcacheUtil;import com.wlyd.fmcgwms.util.sysinit.InitSysProperties;/** * SAAS Token管理工具 *  * @packge com.wlyd.wmscloud.util.SAASTokenManager * @date 2016年5月6日 上午10:20:01 * @author pengjunlin * @comment * @update */public class SAASTokenManager {/** * Token存储对象,保持100000个并发容量(K-useraccount@corCode,V-token) */private static final Map<String, Object> map = new ConcurrentHashMap<String, Object>(100000);/** * 获取用户Token *  * @MethodName: getToken * @Description: * @param key * @return * @throws */public static AccessToken getToken(String key) {if (map.containsKey(key)) {return (AccessToken) map.get(key);}return null;}/** * 添加用户token *  * @MethodName: putToken * @Description: * @param key *            useraccount@corCode * @param accessToken * @throws */public static void putToken(String key, AccessToken accessToken) {map.put(key, accessToken);}/** * 移除token *  * @MethodName: removeToken * @Description: * @param key *            useraccount@corCode * @throws */public static void removeToken(String key) {if (map.containsKey(key)) {map.remove(key);}}/** * 验证Token是否过期 *  * @MethodName: isVlidateToken * @Description: * @param key *            useraccount@corCode * @return * @throws */public static boolean isVlidateToken(String key) {if (map.containsKey(key)) {AccessToken accessToken = (AccessToken) map.get(key);long currentTimestamp = new Date().getTime();// 有效时间两小时if (accessToken.getLongTime() - currentTimestamp > 2 * 3600 * 1000) {return false;}return true;}return false;}/** * 更新Token *  * @MethodName: reputToken * @Description: * @param key *            useraccount@corCode * @param accessToken * @return * @throws */public static void reputToken(String key, AccessToken accessToken) {if (map.containsKey(key)) {putToken(key, accessToken);}}/** * 更新Token *  * @MethodName: reputToken * @Description: * @param key *            useraccount@corCode * @param tokenStr * @return * @throws */public static void reputToken(String key, String tokenStr) {if (map.containsKey(key)) {AccessToken accessToken = new AccessToken();accessToken.setToken(tokenStr);accessToken.setTimestamp(new Timestamp(new Date().getTime()));putToken(key, accessToken);}}/** * 是否包含用户token * @MethodName: iscontainKey  * @Description:  * @param key *          useraccount@corCode * @return * @throws */public static boolean iscontainKey(String key){return map.containsKey(key);}/** * 生成RSA加密 Token *  * @MethodName: generateToken  * @Description:  * @param platformCode * @param tenantCode * @return * @throws */public static String generateToken(String publicKey,String platformCode,String tenantCode){String str=platformCode+"$"+tenantCode+"$"+new Date().getTime();try {byte [] bytes= RSAUtils.encryptByPublicKey(str.getBytes(),publicKey);//return new String( bytes ,"UTF-8");return Base64Utils.encode(bytes);} catch (Exception e) {e.printStackTrace(); }return null;}/** * 生成RSA加密 Token *  * @MethodName: generateBytesToken  * @Description:  * @param platformCode * @param tenantCode * @return * @throws */public static byte [] generateBytesToken(String publicKey,String platformCode,String tenantCode){byte [] bytes=new byte[0];String str=platformCode+"$"+tenantCode+"$"+new Date().getTime();try {bytes= RSAUtils.encryptByPublicKey(str.getBytes(),publicKey);return bytes;} catch (Exception e) {e.printStackTrace(); }return null;}/** * 生成RSA加密 Token *  * @MethodName: generateBytesToken  * @Description:  * @param platformCode * @param tenantCode * @param regex * @return * @throws */public static byte [] generateBytesToken(String publicKey,String platformCode,String tenantCode,String regex){byte [] bytes=new byte[0];String str=platformCode+regex+tenantCode+regex+new Date().getTime();try {bytes= RSAUtils.encryptByPublicKey(str.getBytes(),publicKey);return bytes;} catch (Exception e) {e.printStackTrace(); }return null;}/** * 模拟自动生成Token *  * @MethodName: getToken  * @Description:  * @return * @throws */public  static String getToken(){// 开启线程同步库存数据到OMS/*Map<String, Object> keyMap=null;try {keyMap = RSAUtils.genKeyPair();} catch (Exception e) {e.printStackTrace();}String publicKey=null;try {publicKey = RSAUtils.getPublicKey(keyMap);} catch (Exception e) {e.printStackTrace();}String privateKey=null;try {privateKey = RSAUtils.getPrivateKey(keyMap);} catch (Exception e) {e.printStackTrace();}*/String token=null;try {String publicKey=EhcacheUtil.get("OMS_RSA_PUBLIC_KEY").toString();//String privateKey=EhcacheUtil.get("OMS_RSA_PRIVATE_KEY").toString();String platformCode = (String) EhcacheUtil.get("WAAS_PLATFORMCODE");String memberCode =  InitSysProperties.getUpperCaseFromEhcache(StaticProperty.WAAS_MEMBERCODE);token = SAASTokenManager.generateToken(publicKey, platformCode, memberCode);if(token!=null){token.replaceAll("\\n", "");token.replaceAll("\\r", "");}} catch (Exception e) { Log.getLogger(SAASTokenManager.class).error("Token Error:"+e.getMessage());e.printStackTrace();}return token;}/** * 解密Token *  * @MethodName: decryptToken  * @Description:  * @param privateKey * @param token * @param regex * @return * @throws */public static String [] decryptToken(String privateKey,String token,String regex){String params[]=new String[0];try {String[] strArr = token.split(" ");                int len = strArr.length;                // 转回bytes        byte[] clone = new byte[len];                 for (int i = 0; i < len; i++) {             clone[i] = Byte.parseByte(strArr[i]);        }        String decryptedToken=new String(RSAUtils.decryptByPrivateKey(clone, privateKey));params=decryptedToken.split(regex);} catch (Exception e) {e.printStackTrace();}return params;}/** * @throws Exception  * 测试函数入口 *  * @MethodName: main * @Description: * @param args * @throws */public static void main(String[] args) throws Exception {System.out.println(Md5.getMD5Str("123456"));String key = "wmsadmin@10000"; AccessToken accessToken = new AccessToken();accessToken.setToken("token==xxjisifdihfifdds");accessToken.setTimestamp(new Timestamp(new Date().getTime()));putToken(key, accessToken);AccessToken accessToken2 = getToken(key);System.out.println("token:" + accessToken2.getToken());System.out.println("isValidate:" + isVlidateToken(key));Map<String, Object> keyMap=RSAUtils.genKeyPair();String publicKey=RSAUtils.getPublicKey(keyMap);String privateKey=RSAUtils.getPrivateKey(keyMap);System.out.println("publicKey:\n"+publicKey);System.out.println("privateKey:\n"+privateKey);String token=generateToken(publicKey,"1234", "10000");byte [] bitesToken=RSAUtils.encryptByPublicKey(("1234$10000$"+new Date().getTime()).getBytes(), publicKey);System.out.println("RSA Token:"+token);System.out.println("RSA bites Token加密:"+new String(bitesToken,"UTF-8")); System.out.println("RSA bites Token解密:"+new String(RSAUtils.decryptByPrivateKey(bitesToken, privateKey))); System.out.println("加密:"+new String(RSAUtils.encryptByPublicKey("this is data".getBytes(), publicKey),"UTF-8"));System.out.println("明文:"+new String(RSAUtils.decryptByPrivateKey(RSAUtils.encryptByPublicKey("this is data".getBytes(), publicKey), privateKey)));}}

本文中所述的token我并没有保存下来,而是客户端每次来了都进行验证。

Ehcache缓存请求30s验重

缓存方案你也可以用Redis来做,这里因为项目使用的是Ehcache故将就之。
ehcahe配置:ehcache.xml

<?xml version="1.0" encoding="UTF-8"?><!-- 分布式缓存对象同步  采用RMI方式  官方还提供其他同步方式  此处略 --><ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:noNamespaceSchemaLocation="ehcache.xsd"         updateCheck="true" monitoring="autodetect"         dynamicConfig="true"> <!-- <diskStore path="java.io.tmpdir" /> --><!--1. 指定除自身之外的网络群体中其他提供同步的主机列表,用“|”分开不同的主机 --><!-- <cacheManagerPeerProviderFactoryclass="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"properties="peerDiscovery=manual,rmiUrls=//10.100.0.60:40004/metaCache" /> --><!--2. 配宿主主机配置监听程序,来发现其他主机发来的同步请求 --><!-- <cacheManagerPeerListenerFactoryclass="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"properties="port=40004,socketTimeoutMillis=120000" />此处默认8000端口 --><!-- 默认缓存 --><defaultCache maxElementsInMemory="10000" eternal="false"timeToIdleSeconds="1800" overflowToDisk="true"diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"diskPersistent="false" diskExpiryThreadIntervalSeconds="120"memoryStoreEvictionPolicy="LRU"></defaultCache><!-- 缓存 --><cache name="metaCache" maxElementsInMemory="1000" eternal="false"timeToIdleSeconds="0" overflowToDisk="false"diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"diskPersistent="false" diskExpiryThreadIntervalSeconds="120"memoryStoreEvictionPolicy="LRU"><!-- <cacheEventListenerFactory    class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" properties="replicateAsynchronously=true,  replicatePuts=false,  replicateUpdates=true, replicateUpdatesViaCopy=true,  replicateRemovals=true "/><bootstrapCacheLoaderFactoryclass="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"properties="bootstrapAsynchronously=false" /> --></cache><cache name="REQUESTCACHE" maxElementsInMemory="100000" eternal="false"timeToIdleSeconds="30" timeToLiveSeconds="30" overflowToDisk="false"maxElementsOnDisk="0" diskPersistent="false"diskExpiryThreadIntervalSeconds="0" memoryStoreEvictionPolicy="LRU"></cache></ehcache>

Ehcache工具类:

package com.wlyd.fmcgwms.util.ehcache;import net.sf.ehcache.Cache;import net.sf.ehcache.CacheManager;import net.sf.ehcache.Element;/** * ehcache 缓存工具类 *  * @packge com.wlyd.fmcgwms.util.ehcache.EhcacheUtil * @date 2016年4月28日 下午4:11:27 * @author pengjunlin * @comment cacheName在ehcache.xml中配置 * @update 添加注释,代码重构删除原有类com。wlyd.fmcgwms.util.ehcache.EhcacheUtilOverWrite */public class EhcacheUtil {public static CacheManager manager = CacheManager.create();// 缓存管理public static String cacheName = "metaCache";// 缓存名称/** * 获取缓存对象 *  * @MethodName: get * @Description: * @param key * @return * @throws */public static Object get(Object key) {Cache cache = manager.getCache(cacheName);if (cache != null) {Element element = cache.get(key);if (element != null) {return element.getObjectValue();}}return null;}/** * 获取缓存对象 *  * @MethodName: get * @Description: * @param cacheName * @param key * @return * @throws */public static Object get(String cacheName, Object key) {Cache cache = manager.getCache(cacheName);if (cache != null) {Element element = cache.get(key);if (element != null) {return element.getObjectValue();}}return null;}/** * 添加缓存对象 *  * @MethodName: put * @Description: * @param key * @param value * @throws */public static void put(Object key, Object value) {Cache cache = manager.getCache(cacheName);if (cache != null) {cache.put(new Element(key, value));}}/** * 添加缓存对象 *  * @MethodName: put * @Description: * @param cacheName * @param key * @param value * @throws */public static void put(String cacheName, Object key, Object value) {Cache cache = manager.getCache(cacheName);if (cache != null) {cache.put(new Element(key, value));}}/** * 移出缓存对象 *  * @MethodName: remove * @Description: * @param key * @return * @throws */public static boolean remove(Object key) {Cache cache = manager.getCache(cacheName);if (cache != null) {return cache.remove(key);}return false;}/** * 移除缓存对象 *  * @MethodName: remove * @Description: * @param cacheName * @param key * @return * @throws */public static boolean remove(String cacheName, Object key) {Cache cache = manager.getCache(cacheName);if (cache != null) {return cache.remove(key);}return false;}}



测试方法:

package fmcgwms;import org.apache.http.client.methods.HttpGet;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import com.alibaba.fastjson.JSONObject;import com.wlyd.fmcgwms.util.Md5;import com.wlyd.fmcgwms.util.SAASTokenManager;import com.wlyd.fmcgwms.util.StaticProperty;import com.wlyd.fmcgwms.util.api.APIHttpClient;import com.wlyd.fmcgwms.util.api.RSAUtils;import com.wlyd.fmcgwms.util.ehcache.EhcacheUtil;/** * 开放接口对外模拟测试 * @package fmcgwms.OpenApiTest * @date   2017年3月15日  下午5:51:03 * @author pengjunlin * @comment    * @update */@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations = "classpath:applicationContext.xml")public class OpenApiTest {
        @Testpublic void testEchcacheToTimeout(){String requestSequence=Md5.getMD5Str("localhost&interface&opt_type&uniquecode");System.out.println(">>>>>原始MD5串:"+requestSequence); EhcacheUtil.put(StaticProperty.REQUESTCACHE, requestSequence, requestSequence);System.out.println(">>>>>缓存:"+EhcacheUtil.get(StaticProperty.REQUESTCACHE, requestSequence)); try {Thread.sleep(31000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(">>>>>30s后缓存:"+EhcacheUtil.get(StaticProperty.REQUESTCACHE, requestSequence)); try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}


Ehcache的输出:

>>>>>原始MD5串:cae76d65fc5c47875730ed35a262abb4>>>>>缓存:cae76d65fc5c47875730ed35a262abb42017-03-16 15:13:49,647 [net.sf.ehcache.CacheManager@2f1a74d1] INFO  [net.sf.ehcache.util.UpdateChecker] - This is the latest GA release.2017-03-16 15:14:00,016 [SpringJobSchedulerFactoryBean_Worker-1] ERROR [com.wlyd.fmcgwms.persistence.beans.platform.job.CycleFetchInterfaceInfoTaskJob] - >>>WMS-WAAS接口定时任务<<启动失败---fetch----:请设置WAAS_API_ISENABLE=true2017-03-16 15:14:00,016 [SpringJobSchedulerFactoryBean_Worker-2] ERROR [com.wlyd.fmcgwms.persistence.beans.platform.job.CycleSendInterfaceInfoTaskJob] - >>>WMS-WAAS定时任务<<启动失败----send---:请设置WAAS_API_ISENABLE=true>>>>>30s后缓存:null


0 0
原创粉丝点击