通过配置的方式为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.
*/
@Configuration
public 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
*/
@Component
public 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
Map<String, String> paramMap = 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<String, String> getParamFromArgs(Object[] args) throws ATDException {
Map<String, String> paramMap = new HashMap<String, String>();
//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<String, String> 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
<bean id = "aspectExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<!-- 线程池维护线程的最少数量 -->
<property name ="corePoolSize" value ="5" />
<!-- 线程池维护线程所允许的空闲时间 简单操作不允许超过200ms的处理时间-->
<property name ="keepAliveSeconds" value ="200" />
<!-- 线程池维护线程的最大数量 -->
<property name ="maxPoolSize" value ="50" />
<!-- 线程池所使用的缓冲队列 -->
<property name ="queueCapacity" value ="200" />
</bean>
4、apiAuth
/**
* 需要进行鉴权的接口
* Created by ysma on 2016/9/9.
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @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));
}
}