Spring设计安全的Restful接口
来源:互联网 发布:淘宝宝贝描述制作软件 编辑:程序博客网 时间:2024/05/18 02:30
设计安全的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;// 私钥
- @Override
- public 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超时验证20s
- long 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;
- }
- @Override
- public 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);
- }
- @Override
- public 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")
- @ResponseBody
- public 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")
- @ResponseBody
- public 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. 指定除自身之外的网络群体中其他提供同步的主机列表,用“|”分开不同的主机 -->
- <!-- <cacheManagerPeerProviderFactory
- class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
- properties="peerDiscovery=manual,rmiUrls=//10.100.0.60:40004/metaCache" /> -->
- <!--2. 配宿主主机配置监听程序,来发现其他主机发来的同步请求 -->
- <!-- <cacheManagerPeerListenerFactory
- class="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 "/>
- <bootstrapCacheLoaderFactory
- class="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 {
- @Test
- ublic 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
- >>>>>缓存:cae76d65fc5c47875730ed35a262abb4
- 2017-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=true
- 2017-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
转载自:http://blog.csdn.net/boonya/article/details/62423737
阅读全文
0 0
- Spring设计安全的Restful接口
- Spring设计安全的Restful接口-无用户状态的安全
- Restful风格的接口设计
- RestFul接口的安全验证事例
- RestFul接口的安全验证事例
- RESTFUL API 安全设计
- RESTFUL API 安全设计
- RESTful的Api设计之统一接口
- 关于RESTful接口api的设计
- Restful接口设计
- RESTful API接口设计
- 使用SpringSecurity和SpringMVC来实现安全的RESTFul接口
- 使用token和SpringMVC来实现安全的RESTFul接口
- APP接口的安全设计
- RESTFUL API 安全设计指南
- RESTFUL API 安全设计指南
- Spring RestTemplate 访问 restFul 接口
- 使用CXF+spring+restful创建一个web的接口项目
- 获得60美元,还能在DigitalOcean上免费申请VPS
- 不同jquery插件 版本不同造成的问题
- Hybrid APP
- supervisord 启动elasticsearch 失败
- 学习PHP设计模式之观察者模式
- Spring设计安全的Restful接口
- 高斯滤波分离滤波加速
- 运维相关
- ITSM财报告诉你,没有AI就别谈云计算了!
- ConfigParser模块教程
- java网络编程+通讯协议的理解
- Kafka三款监控工具比较(转)
- 制作加载从模糊到清晰的图片
- css3动画相关