1. 程式人生 > >Spring設計安全的Restful介面

Spring設計安全的Restful介面

設計安全的Restful介面:無使用者互動狀態的介面安全設計。我們需要實現UR攔截請求攔截,介面接入授權驗證和請求驗重。本文中不涉及任何使用者校驗。

設計原理

1.UR攔截請求攔截:通過URL進行攔截過濾;

2.接入授權驗證:驗證請求頭Token;

3.請求驗重:驗證請求序列Sequence;

注:文件禁用於商業用途!

安全過濾器

print?
  1. package com.wlyd.fmcgwms.util.security;  
  2. import java.io.IOException;  
  3. import java.io.PrintWriter;  
  4. import javax.servlet.Filter;  
  5. import javax.servlet.FilterChain;  
  6. import javax.servlet.FilterConfig;  
  7. import javax.servlet.ServletException;  
  8. import javax.servlet.ServletRequest;  
  9. import javax.servlet.ServletResponse;  
  10. import javax.servlet.http.HttpServletRequest;  
  11. import javax.servlet.http.HttpServletResponse;  
  12. import com.alibaba.fastjson.JSONObject;  
  13. import com.wlyd.fmcgwms.util.Log;  
  14. import com.wlyd.fmcgwms.util.SAASTokenManager;  
  15. import com.wlyd.fmcgwms.util.StaticProperty;  
  16. import com.wlyd.fmcgwms.util.api.RSAUtils;  
  17. import com.wlyd.fmcgwms.util.ehcache.EhcacheUtil;  
  18. import com.wlyd.fmcgwms.util.sysinit.InitSysProperties;  
  19. /** 
  20.  * 介面安全過濾器 
  21.  *  
  22.  * @package com.wlyd.fmcgwms.util.security.SecurityFilter
     
  23.  * @date   2017年3月15日  下午1:57:18 
  24.  * @author pengjunlin 
  25.  * @comment    
  26.  * @update 
  27.  */
  28. publicclass SecurityFilter implements Filter {  
  29.     privatestatic String API_ISENABLE ;// WMS是否開通對外介面
  30.     privatestatic String API_PALTFORM;// WMS開放的平臺編碼
  31.     privatestatic String API_MEMBERCODE;//WMS開放的服務商編碼
  32.     privatestatic String publicKey;// 公鑰
  33.     privatestatic String privateKey;// 私鑰
  34.     @Override
  35.     publicvoid destroy() {  
  36.         // TODO Auto-generated method stub
  37.     }  
  38.     /** 
  39.      * 驗證配置是否規範 
  40.      *  
  41.      * @MethodName: isConfiged  
  42.      * @Description:  
  43.      * @param platformCode 
  44.      * @param memberCode 
  45.      * @return 
  46.      * @throws 
  47.      */
  48.     privateboolean isConfiged(String platformCode,String memberCode){  
  49.         if(API_ISENABLE==null||!API_ISENABLE.equals("true")){  
  50.             returnfalse;  
  51.         }  
  52.         if(API_PALTFORM==null||platformCode==null||!platformCode.equals(API_PALTFORM)){  
  53.             returnfalse;  
  54.         }  
  55.         if (API_MEMBERCODE==null||memberCode == null||! memberCode.equals(API_MEMBERCODE)) {  
  56.             returnfalse;  
  57.         }  
  58.         returntrue;  
  59.     }  
  60.     /** 
  61.      * 驗證token是否有效 
  62.      *  
  63.      * @MethodName: validateToken  
  64.      * @Description:  
  65.      * @param token 
  66.      * @return 
  67.      * @throws 
  68.      */
  69.     privateboolean validateToken(String token){  
  70.         if(token==null||token.equals("")){  
  71.             returnfalse;  
  72.         }  
  73.         String params[]=SAASTokenManager.decryptToken(privateKey, token, "&");  
  74.         if(params==null||params.length<3){  
  75.             returnfalse;  
  76.         }  
  77.         long now=System.currentTimeMillis();  
  78.         // Token超時驗證20s
  79.         long seconds=(now-Long.valueOf(params[2]))/1000;  
  80.         if(!API_PALTFORM.equals(params[0])||!API_MEMBERCODE.equals(params[1])||seconds>20){  
  81.             returnfalse;  
  82.         }  
  83.         returntrue;  
  84.     }  
  85.     /** 
  86.      * 驗證請求是否重複 
  87.      *  
  88.      * @MethodName: validateSequece  
  89.      * @Description:  
  90.      * @param sequence 
  91.      * @return 
  92.      * @throws 
  93.      */
  94.     publicboolean validateSequece(String sequence){  
  95.         if(sequence==null||sequence.equals("")){  
  96.             returnfalse;  
  97.         }  
  98.         String requestSequence=(String) EhcacheUtil.get(StaticProperty.REQUESTCACHE, sequence);  
  99.         // 請求序列相同驗證失敗
  100.         if(requestSequence!=null&&sequence.equals(requestSequence)){  
  101.             returnfalse;  
  102.         }  
  103.         returntrue;  
  104.     }  
  105.     @Override
  106.     publicvoid doFilter(ServletRequest request, ServletResponse response,  
  107.             FilterChain chain) throws IOException, ServletException {  
  108.         PrintWriter out = null;  
  109.         HttpServletRequest req = (HttpServletRequest) request;  
  110.         HttpServletResponse res = (HttpServletResponse) response;  
  111.         String platformCode = req.getHeader("PlatformCode");  
  112.         String memberCode = req.getHeader("MemberCode");  
  113.         String token = req.getHeader("Token");  
  114.         String sequence = req.getHeader("Sequence");  
  115.         //String path = req.getServletPath();
  116.         try {  
  117.             byte [] bytes=SAASTokenManager.generateBytesToken(publicKey, platformCode, memberCode,"&");  
  118.             token = RSAUtils.bytesToString(bytes);  
  119.         } catch (Exception e1) {  
  120.             e1.printStackTrace();  
  121.         }  
  122.         // 驗證介面是否配置正確 
  123.         if(!isConfiged(platformCode, memberCode)){  
  124.             JSONObject json = new JSONObject();  
  125.             json.put("IsSuccess""false");  
  126.             json.put("OperationDesc""API parameters are not configed right! ");  
  127.             json.put("ResultCode", ResultCode.OPEN_API_CONFIG_ERROR);  
  128.             try {  
  129.                 out = res.getWriter();  
  130.                 out.write(json.toJSONString());  
  131.             } catch (Exception e) {  
  132.                 e.printStackTrace();  
  133.             }  
  134.             return;  
  135.         }  
  136.         // 驗證Token是否合法
  137.         if(!validateToken(token)){  
  138.             JSONObject json = new JSONObject();  
  139.             json.put("IsSuccess""false");  
  140.             json.put("OperationDesc""Unauthorized:Token is invalid!");  
  141.             json.put("ResultCode", ResultCode.OPEN_API_TOKEN_INVALID);  
  142.             try {  
  143.                 out = res.getWriter();  
  144.                 out.write(json.toJSONString());  
  145.             } catch (Exception e) {  
  146.                 e.printStackTrace();  
  147.             }  
  148.             return;  
  149.         }  
  150.         // 驗證Sequence是否合法
  151.         if(!validateSequece(sequence)){  
  152.             JSONObject json = new JSONObject();  
  153.             json.put("IsSuccess""false");  
  154.             json.put("OperationDesc""Refused:request API too frequently!");  
  155.             json.put("ResultCode", ResultCode.OPEN_API_REQUEST_REQUENTLY);  
  156.             try {  
  157.                 out = res.getWriter();  
  158.                 out.write(json.toJSONString());  
  159.             } catch (Exception e) {  
  160.                 e.printStackTrace();  
  161.             }  
  162.             return;  
  163.         }  
  164.         chain.doFilter(request, response);  
  165.     }  
  166.     @Override
  167.     publicvoid init(FilterConfig arg0) throws ServletException {  
  168.         Log.getLogger(getClass()).info(">>>SecurityFilter invoke init method。。。。。。。。。START!");   
  169.         API_ISENABLE = InitSysProperties.getLowerCaseFromEhcache(StaticProperty.WMS_OPEN_API_ISENABLE);  
  170.         API_PALTFORM = InitSysProperties.getUpperCaseFromEhcache(StaticProperty.WMS_OPEN_API_PLATFORM);  
  171.         API_MEMBERCODE = InitSysProperties.getUpperCaseFromEhcache(StaticProperty.WMS_OPEN_API_MEMBERCODE);  
  172.         publicKey=EhcacheUtil.get(StaticProperty.WMS_OPEN_API_RSA_PUBLIC_KEY).toString();  
  173.         privateKey=EhcacheUtil.get(StaticProperty.WMS_OPEN_API_RSA_PRIVATE_KEY).toString();  
  174.         Log.getLogger(getClass()).info(">>>SecurityFilter invoke init method。。。。。。。。。SUCCESS!");   
  175.     }  
  176. }  
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配置過濾器

print?
  1. <filter>
  2.         <filter-name>SecurityFilter</filter-name>
  3.         <filter-class>com.wlyd.fmcgwms.util.security.SecurityFilter</filter-class>
  4.     </filter>
  5.     <filter-mapping>
  6.         <filter-name>SecurityFilter</filter-name>
  7.         <url-pattern>/openapi/*</url-pattern>
  8.     </filter-mapping>
<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介面

print?
  1. package com.wlyd.fmcgwms.controller.security;  
  2. import java.util.HashMap;  
  3. import java.util.Map;  
  4. import org.springframework.stereotype.Controller;  
  5. import org.springframework.web.bind.annotation.RequestMapping;  
  6. import org.springframework.web.bind.annotation.ResponseBody;  
  7. import com.wlyd.fmcgwms.controller.BaseController;  
  8. import com.wlyd.fmcgwms.util.Tools;  
  9. /** 
  10.  * 開放API控制層 
  11.  *  
  12.  * @package com.wlyd.fmcgwms.controller.platform.OpenAPIController 
  13.  * @date   2017年3月14日  下午4:52:12 
  14.  * @author pengjunlin 
  15.  * @comment    
  16.  * @update 
  17.  */
  18. @Controller
  19. @RequestMapping("/openapi")  
  20. publicclass OpenAPIController extends BaseController{  
  21.     /** 
  22.      * 未授權 
  23.      *  
  24.      * @MethodName: unauthenticated  
  25.      * @Description:  
  26.      * @return 
  27.      * @throws 
  28.      */
  29.     @RequestMapping("/unauthenticated")  
  30.     @ResponseBody
  31.     public String unauthenticated(){  
  32.         Map<String,Object> map=new HashMap<String, Object>();  
  33.         map.put("IsSuccess""false");  
  34.         map.put("OperationDesc""Unauthenticated:Please contact to WMS developers!");  
  35.         return Tools.toJson(map);  
  36.     }  
  37.     /** 
  38.      * 授權成功 
  39.      *  
  40.      * @MethodName: success  
  41.      * @Description:  
  42.      * @return 
  43.      * @throws 
  44.      */
  45.     @RequestMapping("/success")  
  46.     @ResponseBody
  47.     public String success(){  
  48.         Map<String,Object> map=new HashMap<String, Object>();  
  49.         map.put("IsSuccess""true");  
  50.         map.put("OperationDesc""Authenticated!");  
  51.         return Tools.toJson(map);  
  52.     }  
  53. }  
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加密工具

print?
  1. package com.wlyd.fmcgwms.util.api;  
  2. import java.io.ByteArrayOutputStream;  
  3. import java.security.Key;  
  4. import java.security.KeyFactory;  
  5. import java.security.KeyPair;  
  6. import java.security.KeyPairGenerator;  
  7. import java.security.PrivateKey;  
  8. import java.security.PublicKey;  
  9. import java.security.Signature;  
  10. import java.security.interfaces.RSAPrivateKey;  
  11. import java.security.interfaces.RSAPublicKey;  
  12. import java.security.spec.PKCS8EncodedKeySpec;  
  13. import java.security.spec.X509EncodedKeySpec;  
  14. import java.util.HashMap;  
  15. import java.util.Map;  
  16. import javax.crypto.Cipher;  
  17. /** 
  18.  * <p> 
  19.  * RSA公鑰/私鑰/簽名工具包 
  20.  * </p> 
  21.  * <p> 
  22.  * 羅納德·李維斯特(Ron [R]ivest)、阿迪·薩莫爾(Adi [S]hamir)和倫納德·阿德曼(Leonard [A]dleman) 
  23.  * </p> 
  24.  * <p> 
  25.  * 字串格式的金鑰在未在特殊說明情況下都為BASE64編碼格式<br/> 
  26.  * 由於非對稱加密速度極其緩慢,一般檔案不使用它來加密而是使用對稱加密,<br/> 
  27.  * 非對稱加密演算法可以用來對對稱加密的金鑰加密,這樣保證金鑰的安全也就保證了資料的安全 
  28.  * </p> 
  29.  *  
  30.  * @author IceWee 
  31.  * @date 2012-4-26 
  32.  * @version 1.0 
  33.  */
  34. publicclass RSAUtils {  
  35.     /** 
  36.      * 加密演算法RSA 
  37.      */
  38.     publicstaticfinal String KEY_ALGORITHM = "RSA";  
  39.     /** 
  40.      * 簽名演算法 
  41.      */
  42.     publicstaticfinal String SIGNATURE_ALGORITHM = "MD5withRSA";  
  43.     /** 
  44.      * 獲取公鑰的key 
  45.      */
  46.     privatestaticfinal String PUBLIC_KEY = "RSAPublicKey";  
  47.     /** 
  48.      * 獲取私鑰的key 
  49.      */
  50.     privatestaticfinal String PRIVATE_KEY = "RSAPrivateKey";  
  51.     /** 
  52.      * RSA最大加密明文大小 
  53.      */
  54.     privatestaticfinalint MAX_ENCRYPT_BLOCK = 117;  
  55.     /** 
  56.      * RSA最大解密密文大小 
  57.      */
  58.     privatestaticfinalint MAX_DECRYPT_BLOCK = 128;  
  59.     /** 
  60.      * <p> 
  61.      * 生成金鑰對(公鑰和私鑰) 
  62.      * </p> 
  63.      *  
  64.      * @return 
  65.      * @throws Exception 
  66.      */
  67.     publicstatic Map<String, Object> genKeyPair() throws Exception {  
  68.         KeyPairGenerator keyPairGen = KeyPairGenerator  
  69.                 .getInstance(KEY_ALGORITHM);  
  70.         keyPairGen.initialize(1024);  
  71.         KeyPair keyPair = keyPairGen.generateKeyPair();  
  72.         RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  
  73.         RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();  
  74.         Map<String, Object> keyMap = new HashMap<String, Object>(2);  
  75.         keyMap.put(PUBLIC_KEY, publicKey);  
  76.         keyMap.put(PRIVATE_KEY, privateKey);  
  77.         return keyMap;  
  78.     }  
  79.     /** 
  80.      * <p> 
  81.      * 用私鑰對資訊生成數字簽名 
  82.      * </p> 
  83.      *  
  84.      * @param data 
  85.      *            已加密資料 
  86.      * @param privateKey 
  87.      *            私鑰(BASE64編碼) 
  88.      *  
  89.      * @return 
  90.      * @throws Exception 
  91.      */
  92.     publicstatic String sign(byte[] data, String privateKey) throws Exception {  
  93.         byte[] keyBytes = Base64Utils.decode(privateKey);  
  94.         PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);  
  95.         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);  
  96.         PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);  
  97.         Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);  
  98.         signature.initSign(privateK);  
  99.         signature.update(data);  
  100.         return Base64Utils.encode(signature.sign());  
  101.     }  
  102.     /** 
  103.      * <p> 
  104.      * 校驗數字簽名 
  105.      * </p> 
  106.      *  
  107.      * @param data 
  108.      *            已加密資料 
  109.      * @param publicKey 
  110.      *            公鑰(BASE64編碼) 
  111.      * @param sign 
  112.      *            數字簽名 
  113.      *  
  114.      * @return 
  115.      * @throws Exception 
  116.      *  
  117.      */
  118.     publicstaticboolean verify(byte[] data, String publicKey, String sign)  
  119.             throws Exception {  
  120.         byte[] keyBytes = Base64Utils.decode(publicKey);  
  121.         X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);  
  122.         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);  
  123.         PublicKey publicK = keyFactory.generatePublic(keySpec);  
  124.         Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);  
  125.         signature.initVerify(publicK);  
  126.         signature.update(data);  
  127.         return signature.verify(Base64Utils.decode(sign));  
  128.     }  
  129.     /** 
  130.      * <P> 
  131.      * 私鑰解密 
  132.      * </p> 
  133.      *