通过配置的方式为bean自动创建拦截器,代码简例:
AppConfig:
import org.aopalliance.aop.Advice;import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/** * Created by ysma on 2016/8/16. */@Configurationpublic class AppConfig { //要创建代理的目标Bean @Bean public UserService userService(){ return new UserServiceImpl(); } //创建Advice或Advisor @Bean public Advice myMethodInterceptor(){ return new MyMethodInterceptor(); } //使用BeanNameAutoProxyCreator来创建代理 @Bean public BeanNameAutoProxyCreator beanNameAutoProxyCreator(){ BeanNameAutoProxyCreator beanNameAutoProxyCreator=new BeanNameAutoProxyCreator(); //设置要创建代理的那些Bean的名字 beanNameAutoProxyCreator.setBeanNames(new String[]{"userSer*"}); //设置拦截链名字(这些拦截器是有先后顺序的) beanNameAutoProxyCreator.setInterceptorNames(new String[]{"myMethodInterceptor"}); beanNameAutoProxyCreator.setOptimize(true); return beanNameAutoProxyCreator; }}
main:
public class main { public static void main(String[] args) { ApplicationContext applicationContext=new AnnotationConfigApplicationContext(AppConfig.class); UserService userService= applicationContext.getBean(UserService.class); userService.print(); }}
MyMethodInterceptor:
import org.aopalliance.intercept.MethodInterceptor;import org.aopalliance.intercept.MethodInvocation;/** * Created by ysma on 2016/8/16. */public class MyMethodInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println(getClass()+"调用方法前"); Object ret=invocation.proceed(); System.out.println(getClass()+"调用方法后"); return ret; }}
userservice:
/** * Created by ysma on 2016/8/16. */public interface UserService { void print();}
userserviceImpl:
public class UserServiceImpl implements UserService { public void print(){ //System.out.println(getClass()+"#print"); }}
===================分割线=============================
1、spring注解切面和控制器
@Component@Order(3)public class AuthUtil extends BeanNameAutoProxyCreator implements InitializingBean{ private static final Logger LOGGER = LoggerFactory.getLogger(AuthUtil.class); @Override public void afterPropertiesSet() throws Exception { super.setBeanNames(new String[]{"XXXXController"}); super.setInterceptorNames(new String[]{"asrAuthInterceptor"}); super.setOptimize(true); LOGGER.info("start config interceptor:{} for {}", "asrAuthInterceptor", "silkRoadController"); }}
2、切面编码
/** * @author ysma * @since 2016/9/9 */@Componentpublic class AsrAuthInterceptor implements MethodBeforeAdvice { private static final Logger LOGGER = LoggerFactory.getLogger(AsrAuthInterceptor.class); /**按分钟统计鉴权总数*/ private static final String AUTHTOTAL = "ATD:ASR:AUTH:TOTAL:COUNT"; /**按分钟统计鉴权失败总数*/ private static final String AUTHFAIL = "ATD:ASR:AUTH:FAIL:COUNT"; private static final long SECONDS = 4*60*60; @Resource ThreadPoolTaskExecutor aspectExecutor; @Resource ConfigApi configApi; @Resource UserDAO userDAO; @Resource private RedisManager redisManager; /** * * @param method method being invoked * @param args arguments to the method * @param target target of the method invocation. May be {@code null}. * @throws Throwable if this object wishes to abort the call. * Any exception thrown will be returned to the caller if it's * allowed by the method signature. Otherwise the exception * will be wrapped as a runtime exception. */ @Override public void before(Method method, Object[] args, Object target) throws Throwable { ApiAuth apiAuth = method.getAnnotation(ApiAuth.class); //鉴权开关 String authIt = configApi.get("authIt"); if(apiAuth != null && "true".equals(authIt)){ LOGGER.debug("[AuthInterceptor] 对{}的方法{}进行鉴权", target.getClass().getSimpleName(), method.getName()); countAuth(AUTHTOTAL); //获取报文,获取签名,获取供应商id/采购商id MapparamMap = getParamFromArgs(args); String vendorId = paramMap.get("vendorId"); User user = userDAO.queryUserById(vendorId); String publicKey = user.getPublicKey(); String privateKey = user.getPrivateKey(); if(publicKey == null || privateKey == null){ LOGGER.error("[AuthInterceptor] 供应商Id:{}鉴权失败,原因:密钥缺失", vendorId); countAuth(AUTHFAIL); throw new ATDException("密钥缺失", ErrorCode.KEY_MISS); } else { try { boolean flag = RsaCrypt.verify(publicKey, privateKey, paramMap.get("message"), paramMap.get("sign")); if(!flag){ LOGGER.error("[AuthInterceptor] 供应商Id:{}鉴权失败,原因:报文不一致", vendorId); countAuth(AUTHFAIL); throw new ATDException("报文不一致", ErrorCode.MESSAGE_DIFFERENCE); } } catch (Exception e) { LOGGER.error("[AuthInterceptor] 校验失败:{}", e.getMessage()); countAuth(AUTHFAIL); throw new ATDException("校验失败", ErrorCode.MESSAGE_DIFFERENCE); } } } else { LOGGER.debug("[AuthInterceptor] {}不需要鉴权", target.getClass().getSimpleName()); } } /** * @param args param * @throws ATDException */ private Map getParamFromArgs(Object[] args) throws ATDException { Map paramMap = new HashMap (); //1.get request HttpServletRequest request = getRequest(args); if(request == null){ LOGGER.warn("[AuthInterceptor], 未获取到request参数,请在controller入参中增加HttpServletRequest"); throw new ATDException("request参数缺失", ErrorCode.INTERNAL_ERROR); } getJsonString(request, paramMap); if(paramMap.get("message") == null || paramMap.get("vendorId") == null || paramMap.get("sign") == null){ LOGGER.warn("[AuthInterceptor], 未获取到参数,data:{}, vendorId:{}, sign:{}", paramMap.get("message"), paramMap.get("vendorId"), paramMap.get("sign")); throw new ATDException("请检查data报文和sign签名和采购商id", ErrorCode.MESSAGE_MISS); } return paramMap; } /** * 获取 HttpServletRequest * @param args params * @return HttpServletRequest */ private HttpServletRequest getRequest(Object[] args){ for(Object obj : args){ if(obj instanceof HttpServletRequest){ return (HttpServletRequest)obj; } } return null; } /** * 将对象转换为json报文 * @param request object to converted * @param paramMap vendorId 采购商id; message 报文; sign 签名 */ private void getJsonString(HttpServletRequest request, Map paramMap) throws ATDException { try { String jsonStr = request.getParameter("json"); JSONObject json = JSON.parseObject(jsonStr); paramMap.put("sign", json.getString("sign").replaceAll(" ", "+")); paramMap.put("vendorId", json.getString("purchaseId")); Pattern p = Pattern.compile("\\s*|\t|\r|\n"); Matcher m = p.matcher(jsonStr); String param = m.replaceAll(""); String message = param.substring(param.indexOf("data") - 1, param.length() -1); paramMap.put("message", message); } catch (Exception e) { LOGGER.error("[AuthInterceptor] [getJsonString]拼接参数时出错:{}", e.getMessage()); } } /** * 鉴权计数器 * @param key key */ private void countAuth(final String key){ aspectExecutor.execute(new Runnable() { @Override public void run() { try { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm"); final String hhMm = simpleDateFormat.format(new Date()); if(redisManager.ttl(key) < 0){ //过期 重置 redisManager.delKey(key); redisManager.hIncr(key, hhMm, 1); redisManager.expire(key, SECONDS); } else { redisManager.hIncr(key, hhMm, 1); } } catch (Exception e) { LOGGER.error("[AuthInterceptor] [countAuth]error:{}", e.getMessage()); } } }); }}
3、threadPoolExecutor
4、apiAuth
/** * 需要进行鉴权的接口 * Created by ysma on 2016/9/9. */@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface ApiAuth { /**加密方式*/ String enCodeType() default "RSA";}
5、RsaCrypt
package com.tuniu.air.ticket.channel.auth.crypt;import javax.crypto.Cipher;import java.security.*;import java.security.spec.PKCS8EncodedKeySpec;import java.security.spec.X509EncodedKeySpec;/** * @author ysma * Created on 2016/7/4. */public class RsaCrypt { /** * 用私钥加密 * @param data 加密数据 * @param key 密钥 * @return 密文 * @throws Exception */ public static byte[] encryptByPrivateKey(byte[] data,String key) throws Exception { //解密密钥 byte[] keyBytes = Coder.decryptBASE64(key); //取私钥 PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(RsaConstants.KEY_ALGORTHM); Key privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); //对数据加密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, privateKey); return cipher.doFinal(data); } /** * 用私钥对信息生成数字签名 * @param message //报文 * @param privateKey //私钥 * @return 签名 * @throws Exception 异常 */ public static String sign(String message, String privateKey) throws Exception { String summary = Coder.encryptMD5(message.getBytes()); byte[] bytes = RsaCrypt.encryptByPrivateKey(summary.getBytes(), privateKey); //解密私钥 byte[] keyBytes = Coder.decryptBASE64(privateKey); //构造PKCS8EncodedKeySpec对象 PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes); //指定加密算法 KeyFactory keyFactory = KeyFactory.getInstance(RsaConstants.KEY_ALGORTHM); //取私钥匙对象 PrivateKey privateKey2 = keyFactory.generatePrivate(pkcs8EncodedKeySpec); //用私钥对信息生成数字签名 Signature signature = Signature.getInstance(RsaConstants.SIGNATURE_ALGORITHM); signature.initSign(privateKey2); signature.update(bytes); return Coder.encryptBASE64(signature.sign()); } /** * 校验数字签名 * @param message 报文 * @param publicKey 公钥 * @param privateKey 私钥 * @param sign 数字签名 * @return 校验结果 * @throws Exception */ public static boolean verify(String publicKey, String privateKey, String message, String sign) throws Exception { String summary = Coder.encryptMD5(message.getBytes()); byte[] bytes = RsaCrypt.encryptByPrivateKey(summary.getBytes(), privateKey); //解密公钥 byte[] keyBytes = Coder.decryptBASE64(publicKey); //构造X509EncodedKeySpec对象 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes); //指定加密算法 KeyFactory keyFactory = KeyFactory.getInstance(RsaConstants.KEY_ALGORTHM); //取公钥匙对象 PublicKey publicKey2 = keyFactory.generatePublic(x509EncodedKeySpec); Signature signature = Signature.getInstance(RsaConstants.SIGNATURE_ALGORITHM); signature.initVerify(publicKey2); signature.update(bytes); //验证签名是否正常 return signature.verify(Coder.decryptBASE64(sign)); }}
6、RsaConstant
/** * Created by mayongsheng on 2016/7/4. */public class RsaConstants { public static final String KEY_ALGORTHM="RSA";// public static final String SIGNATURE_ALGORITHM="MD5withRSA"; public static final String PUBLIC_KEY = "publicKey";//公钥 public static final String PRIVATE_KEY = "privateKey";//私钥 /**1day unit:second */ public static final long CACHE_TIME_DAY = 24*60*60; public static final String USER_KEY = "ASR:AUTH:USER:PURCHASE_ID:";}
7、Coder
import org.apache.commons.codec.binary.Base64;import java.security.MessageDigest;public class Coder { public static final String KEY_SHA="SHA"; public static final String KEY_MD5="MD5"; public static final String KEY_BASE64="BASE64"; /** * BASE64解密 * @param key * @return * @throws Exception */ public static byte[] decryptBASE64(String key) throws Exception { return Base64.decodeBase64(key); } /** * BASE64加密 * @param key * @return * @throws Exception */ public static String encryptBASE64(byte[] key)throws Exception { return Base64.encodeBase64String(key); } /** * MD5加密 * @param data * @return * @throws Exception */ public static String encryptMD5(byte[] data)throws Exception { MessageDigest md5 = MessageDigest.getInstance(KEY_MD5); md5.update(data); byte[] mds = md5.digest(); return toHex(mds); } /** * To hex * * @param bytes the bytes * @return the string */ public static String toHex(byte bytes[]){ StringBuilder hstr = new StringBuilder(); String sTmp; for (int n = 0; n < bytes.length; n++) { sTmp = Integer.toHexString(bytes[n] & 0xff); if (sTmp.length() == 1){ hstr.append("0").append(sTmp); } else { hstr.append(sTmp); } } return hstr.toString(); }}
8、AesCrypt
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;import javax.crypto.*;import javax.crypto.spec.SecretKeySpec;import java.io.UnsupportedEncodingException;import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import java.security.SecureRandom;/** * Created by ysma on 2016/9/9. */public class AesCrypt { /** * 加密 * @param content 需要加密的内容 * @param password 加密密码 * @return */ public static byte[] encrypt(String content, String password) { try { KeyGenerator kgen = KeyGenerator.getInstance("AES"); kgen.init(128, new SecureRandom(password.getBytes())); SecretKey secretKey = kgen.generateKey(); byte[] enCodeFormat = secretKey.getEncoded(); SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); Cipher cipher = Cipher.getInstance("AES");// 创建密码器 byte[] byteContent = content.getBytes("utf-8"); cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化 byte[] result = cipher.doFinal(byteContent); return result; // 加密 } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } return null; } /**解密 * @param content 待解密内容 * @param password 解密密钥 * @return */ public static byte[] decrypt(byte[] content, String password) { try { KeyGenerator kgen = KeyGenerator.getInstance("AES"); kgen.init(128, new SecureRandom(password.getBytes())); SecretKey secretKey = kgen.generateKey(); byte[] enCodeFormat = secretKey.getEncoded(); SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); Cipher cipher = Cipher.getInstance("AES");// 创建密码器 cipher.init(Cipher.DECRYPT_MODE, key);// 初始化 byte[] result = cipher.doFinal(content); return result; // 加密 } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } return null; } /**将二进制转换成16进制 * @param buf * @return */ public static String parseByte2HexStr(byte buf[]) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < buf.length; i++) { String hex = Integer.toHexString(buf[i] & 0xFF); if (hex.length() == 1) { hex = '0' + hex; } sb.append(hex.toUpperCase()); } return sb.toString(); } /**将16进制转换为二进制 * @param hexStr * @return */ public static byte[] parseHexStr2Byte(String hexStr) { if (hexStr.length() < 1) return null; byte[] result = new byte[hexStr.length()/2]; for (int i = 0;i< hexStr.length()/2; i++) { int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16); int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16); result[i] = (byte) (high * 16 + low); } return result; } public static void main(String[] args) { String content = "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"; String password = "test"; //加密 System.out.println("加密前:" + content); byte[] encryptResult = encrypt(content, password); String tt4 = Base64.encode(encryptResult); System.out.println(new String(tt4)); //解密 byte[] decryptResult = decrypt(encryptResult,password); System.out.println("解密后:" + new String(decryptResult)); }}