手机号加解密业务,通过aop实现

这篇具有很好参考价值的文章主要介绍了手机号加解密业务,通过aop实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

序言:

在开发过程中因为功能的特殊性  需要对客户信息的手机号进行加密处理 然后存到数据库中,然而这个需求是项目中期加入,很多功能上已经使用了获取客户信息的方法,没法统一控制手机号加解密操作, 于是考虑使用 aop做环绕增强 对所有出参进行,解密操作(这里只对)。

Spring AOP--@Around--使用/实例 使用或理解上的问题

tips: 这里不赘述 注解的含义等基本概念,是以使用@Around为主的新手教程

需要引入jar包

	<!-- #Spring中的切面依赖 -->
	 <dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-aop</artifactId>
	</dependency>

对于aop 网上有很多的代码示例,但是有些看不明白、写得比较含糊的问题列一下

问题1 @Around中的方法名称怎么定义:

@Around("test()")  这个中的  test()方法是自己定义的切面的方法 必须要通过@Pointcut指定切面才能生效

// 指定全局的切面
	@Pointcut("execution (* com.dealer.api.controller.*.*(..))")
	public void test() {

	}


// 环绕增强
	@Around("test()")
	public Object around(ProceedingJoinPoint proceedingJoinPoint) {
		Object proceed = null;
		String className = proceedingJoinPoint.getSignature().getDeclaringTypeName();
		String methodName = proceedingJoinPoint.getSignature().getName();
		System.out.println("============== " + className + " 类中的方法:" + methodName + " 开始执行 ==============");
		MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
		// 参数名称
		String[] parameterNames = methodSignature.getParameterNames();
		// 参数值
		Object[] args = proceedingJoinPoint.getArgs();
		for (int i = 0; i < args.length; i++) {
			System.out.println("第" + i + "个参数:" + "  key:" + parameterNames[i] + "  value:" + args[i]);
		}

		try {
			proceed = proceedingJoinPoint.proceed();
			// ====================== 返回==============================
			System.out.println("执行结果为:" + proceed);

		} catch (Throwable e) {
			e.printStackTrace();
			System.out.println("执行方法发生了错误:" + e.getMessage());
			System.out.println("============== " + className + " 类中的方法:" + methodName + " 执行结束 ==============");
			// return setResultError("执行方法发生了错误:"+e.getMessage());
			return "执行方法发生了错误:" + e.getMessage();
		}
		System.out.println("============== " + className + " 类中的方法:" + methodName + " 执行结束 ==============");
		return proceed;
	}
匹配规则使用技巧:

直接在业务方法上加@Around 注解定义切面 

定义切面的三种匹配示例

一:    // 指定类增强 DealerController 类名  该类下所有方法增强
    // @Around(value = "execution(* com.*..DealerController.*(..))")

二:
    // 指定方法增强  testEncrypt 方法名   所有叫testEncrypt 名字的方法增强
    // @Around(value = "execution(* com.*..*.testEncrypt(..))")

三: // DealerController 类名  该类下所有方法后缀为DealerDecryption的方法 增强
    @Around(value = "execution(* com.*..DealerController.*DealerDecryption(..))")

	// 指定类增强 DealerController 类名
	// @Around(value = "execution(* com.*..DealerController.*(..))")
	// 指定方法增强  testEncrypt 方法名
	// @Around(value = "execution(* com.*..*.testEncrypt(..))")
	@Around(value = "execution(* com.*..DealerController.*DealerDecryption(..))")
	public Object ReturnDecryption(ProceedingJoinPoint proceedingJoinPoint) {
		Object proceed = null;
//		String className = proceedingJoinPoint.getSignature().getDeclaringTypeName();
//		String methodName = proceedingJoinPoint.getSignature().getName();
//		System.out.println("============== " + className + " 类中的方法:" + methodName + " 开始执行 ==============");
//		MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
//		// 参数名称
//		String[] parameterNames = methodSignature.getParameterNames();
//		// 参数值
//		Object[] args = proceedingJoinPoint.getArgs();
//		for (int i = 0; i < args.length; i++) {
//			System.out.println("第" + i + "个参数:" + "  key:" + parameterNames[i] + "  value:" + args[i]);
//		}
		
		try {
			proceed = proceedingJoinPoint.proceed();
			
			
			// ====================== 返回==============================
			System.out.println("执行结果为:" + proceed);

		} catch (Throwable e) {
			log.error("=========ReturnDecryption===========",e);
//			System.out.println("执行方法发生了错误:" + e.getMessage());
//			System.out.println("============== " + className + " 类中的方法:" + methodName + " 执行结束 ==============");
			// return setResultError("执行方法发生了错误:"+e.getMessage());
			return "执行方法发生了错误:" + e.getMessage();
		}
//		System.out.println("============== " + className + " 类中的方法:" + methodName + " 执行结束 ==============");
		return proceed;
	}

到这里切面环绕的功能基本实现了, 开始进入正文对业务参数加解密。

读取返回遇到问题:

在通过 proceed = proceedingJoinPoint.proceed(); 方法获取到了对象后 虽然可以将参数打印出来但是无法修改返回内容和结果,通过对象强转的方式甚至无法获取内容。

解决方式:

1、对打印的结果进行 json格式化操作,获取到具体业务返回的数据

2、返回结果无法修改,只能造一个一样的返回结果体返回出去文章来源地址https://www.toymoban.com/news/detail-666832.html

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import lombok.extern.slf4j.Slf4j;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cre.dmp.osp.common.response.RestResponse;
import com.Dealer.service.RemoteCallService;
import com.*.base.core.util.StringUtils;

/**
 * Title: WebException.java
 * Description: 环绕增强  对客户信息中手机号 做解密操作
 * 
 * @date 2023年7月31日
 */
// 开启切面注解
@Aspect
// lombok日志注解
@Slf4j
// 注入容器,统一管理
@Component
@SuppressWarnings({ "rawtypes", "unchecked" })
public class AopDecrypt {

    @Autowired
    RemoteCallService remoteCallService;
    
	private static String HANDLE_FIELD_NAME = "mobile"; // 特殊处理字段 TODO

	private static final String ENCRYPT_FLAG = "encrypt"; // 加密标识
															// (判断对值进行加密或者解密的操作)

	private static final String DECRYPT_FLAG = "decrypt"; // 解密标识(判断对值进行加密或者解密的操作)
 
	 

	// 指定类增强 DealerController 类名
	// @Around(value = "execution(* com.*..DealerController.*(..))")
	// 指定方法增强  testEncrypt 方法名
	// @Around(value = "execution(* com.*..*.testEncrypt(..))")
	@Around(value = "execution(* com.*..DealerController.*DealerDecryption(..))")
	public Object ReturnDecryption(ProceedingJoinPoint proceedingJoinPoint) {
		Object proceed = null;
//		String className = proceedingJoinPoint.getSignature().getDeclaringTypeName();
//		String methodName = proceedingJoinPoint.getSignature().getName();
//		System.out.println("============== " + className + " 类中的方法:" + methodName + " 开始执行 ==============");
//		MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
//		// 参数名称
//		String[] parameterNames = methodSignature.getParameterNames();
//		// 参数值
//		Object[] args = proceedingJoinPoint.getArgs();
//		for (int i = 0; i < args.length; i++) {
//			System.out.println("第" + i + "个参数:" + "  key:" + parameterNames[i] + "  value:" + args[i]);
//		}
		
		try {
			proceed = proceedingJoinPoint.proceed();
			
			
			ResponseEntity requestParam = (ResponseEntity) proceed;
//			成功 状态为200  
			if (requestParam.getStatusCodeValue() == 200) {
//				RestResponse body = (RestResponse)requestParam.getBody();
				String ss =  JSONObject.toJSONString(requestParam);
				 log.info("返回的结果为:"+JSONObject.toJSONString(requestParam));
				 Object object = JSONObject.parseObject(ss).get("body");
				 Object object2 = JSONObject.parseObject(object.toString()).get("obj") ;
				 
				 Object object3 = JSONObject.parseObject(object2.toString()).get("content") ;
				 if (object3 == null) {
					// 单个对象加密 
					 Object changValue = changValue(object2,DECRYPT_FLAG);
					 //  特殊处理数据
					 proceed = RestResponse.createSuccessRes(changValue);
				}else{
//					分页对象加密
					// list对象加密 
					 Object changValue = changValue(object3,DECRYPT_FLAG);
					
					 // 回填参数
					 JSONObject parseObject = JSON.parseObject(object2.toString());
					 parseObject.put("content", changValue);
					 
					 proceed =RestResponse.createSuccessRes(parseObject);
				}
			} 
			
			// ====================== 返回==============================
			System.out.println("执行结果为:" + proceed);

		} catch (Throwable e) {
			log.error("=========ReturnDecryption===========",e);
//			System.out.println("执行方法发生了错误:" + e.getMessage());
//			System.out.println("============== " + className + " 类中的方法:" + methodName + " 执行结束 ==============");
			// return setResultError("执行方法发生了错误:"+e.getMessage());
			return "执行方法发生了错误:" + e.getMessage();
		}
//		System.out.println("============== " + className + " 类中的方法:" + methodName + " 执行结束 ==============");
		return proceed;
	}

	/***
	 * 
	 * @exception 根据(map\list)类型区分对应的解析对象方法:
	 * @param _obj  内容
	 * @param flag  加密解密 标识字段
	 * @throws Exception
	 *             void
	 */
	private Object changValue(Object _obj, String flag) throws Exception {
		// 基本类型不作操作
		if (_obj instanceof Map) {
			changeMapValue(_obj, flag);
		} else if (_obj instanceof List) {
			List<Object> list = (List<Object>) _obj;
			for (Object obj : list) {
				if (obj instanceof Map) {
					changeMapValue(obj, flag);
				} else {
					changObjectValue(obj, flag);
				}
			}
		} else {
			changObjectValue(_obj, flag);
		}
		return _obj;
	}

	/**
	 * 
	 * @exception 解析map 格式的数据  找的需要加密的字段:
	 * @param _obj
	 * @param flag	加密解密 标识字段
	 * @return Object
	 * @throws Exception
	 */
	private Object changeMapValue(Object _obj, String flag) throws Exception {
		Map<String, Object> map = (Map<String, Object>) _obj;
		if (map.containsKey(HANDLE_FIELD_NAME)) {
			Object fieldValue = map.get(HANDLE_FIELD_NAME);
			String afterValue = crypto(fieldValue, flag);
			if (StringUtils.isNotBlank(afterValue)) {
				map.put(HANDLE_FIELD_NAME, afterValue);
			}
		}
		return _obj;
	}

	/***
	 * 
	 * @exception 解析对象内容 找到需要加密字段:
	 * @param _obj
	 * @param flag	 加密解密 标识字段
	 * @return
	 * @throws Exception  Object
	 */
	private Object changObjectValue(Object _obj, String flag) throws Exception {
		Class<?> resultClz = _obj.getClass();
		Field[] fieldInfo = resultClz.getDeclaredFields(); // 获取class里的所有字段
															// 父类字段获取不到
															// 注:如果出现加密解密失败
															// 请先查看mobile是否在父类中
		for (Field field : fieldInfo) {
			if (HANDLE_FIELD_NAME.equals(field.getName())) {
				field.setAccessible(true); // 成员变量为private,故必须进行此操
				Object fieldValue = field.get(_obj);
				String afterValue = crypto(fieldValue, flag);
				if (StringUtils.isNoneBlank(afterValue)) {
					field.set(_obj, afterValue);
				}else{
					
				}
				break;
			}
		}
		return _obj;
	}
	
    
	/**
	 * 对特殊字段 进行加解密
	 * @param value  加密内容
	 * @param flag	加解密方式
	 * @return
	 * @throws Exception
	 */
	private String crypto(Object value, String flag) throws Exception {
		if (value == null) {
			return null;
		}
		// 加密操作;加密之前先去查询一下数据库 有没有 如果没有 则insert
		if (ENCRYPT_FLAG.equals(flag)) {
			List  e1 = new ArrayList();
	       	e1.add(value);
	   		// 加密
	       	Map<String, String> encrypt = remoteCallService.encrypt(e1);
	       	return encrypt.get(value);
		} else { // 解密操作 通过seq 查询 然后解密返回明文
	       	List  e11 = new ArrayList();
	       	e11.add(value);
	        	// 解密
	   		Map<String, String> decrypt = remoteCallService.decrypt(e11);
	   		
	   		String mobile = decrypt.get(value);
	   		String result = ""; 
	   		if (StringUtils.isNoneBlank(mobile)) {
	   			  result = mobile.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
			}else{
				// 解密失败时  屏蔽手机号
				mobile = value.toString();
				if (mobile.length()==11) {
					result = mobile.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
				}else{
					result =mobile;
				}
			}
	   		
	   		return result;
		}
	}

}

到了这里,关于手机号加解密业务,通过aop实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 微信手机号授权解密失败问题现象和解决方法: getPhoneNumber

    用uniapp 方式获取微信手机号授权,前后花了很大精力在解决解密手机号失败情况,此处加以说明,希望碰到类型情况的网友出坑: button open-type=\\\"getPhoneNumber\\\" @getphonenumber=\\\"getPhoneNumber\\\"微信快捷登录/button 1,第1种解密失败: 问题现象: 第一次解密失败,第二次成功 解决方法:

    2024年02月12日
    浏览(36)
  • django admin后台中进行多个手机号解密消耗时间对比

    需求: 1 手机号在数据库中是使用rsa方式加密存储,后台查看中需要转换为明文,因为需要解密多个手机号,所以在后台查看中消耗时间3秒,希望通过多线程,多进程,异步方式来缩短时间 相关注意点: Django遵循单请求模型,其中每个请求都在单个线程中处理。在Django的请

    2024年01月21日
    浏览(26)
  • 微信小程序中获取用户手机号密文数据解密报错问题

    微信小程序获取手机号,官方通常会返回密文数据给我们,此时就需要我们自行解密数据。在揭秘的数据过程中会发现,第一次授权获取手机号会出现错误,再次获取的时候就能够正常获取。 错误信息一般分两种: 密文后端解密的 javax.crypto.BadPaddingException: pad block corrupted(后

    2024年02月15日
    浏览(46)
  • 使用Spring Boot Security 实现多认证 手机号登录 微信扫码登录 微信扫码注册

    Spring Boot 3.x Spring Security 5.7 Spring Redis MyBatis plus 前端 Vue 公司 最近有个新项目 使用单点登录 sso 百度了一圈 也没怎么找到微信扫码注册的功能于是自己写 需求就是 手机 + 密码登录 微信扫码登录 微信扫码注册 微信二维码 登录 和注册二合一 具体实现 稍后我会说 本教程将指导

    2024年04月10日
    浏览(42)
  • 如何通过QQ进行手机号溯源

    Q绑在线查询: http://2k.24kz.cn/ 如果上述的网址查询不到信息的号。会提示说没有找到 可能说明数据库中并无该qq号所绑定手机号的信息 开始正题: 第一步:点击添加账号,复制其QQ账号进入点击忘记密码,便可查看其手机前3位以及后两位 输入账号 下一步 第二步:使用查询

    2024年02月06日
    浏览(23)
  • 通过蜜罐技术获取攻击者手机号、微信号【网络安全】

    相关声明: 以下内容仅限用于红蓝攻防对抗等专业领域,请勿用于非法用途。 首先,我们先讲一下蜜罐的概念,你可以简单理解较为蜜罐就是一个陷阱,故意暴露一些我们人为设计好的漏洞,让攻击者自投罗网。 蜜罐是对攻击者的欺骗技术,用以监视、检测、分析和溯源攻

    2024年02月12日
    浏览(28)
  • Java获取微信小程序code获取openid、session_key、unionid,获取授权信息解密获取手机号

    WechatUtils (具体实体类自己根据自己的业务需求配置就行) service impl实现类 👆这个代码已经可以解析出code信息,具体的业务流程自己去添加就ok 还是我们之前的WechatUtils,在里面添加getPhone方法 service impl实现类 👆以上就是本次的笔记了,大家有需要用的自取,有用记得点个赞

    2024年02月16日
    浏览(30)
  • uni-app微信小程序获取手机号授权登录(复制即用,js完成敏感数据对称解密,无需走服务端处理)

    目录 一、示例 二、具体实现说明 获取到的手机号 属性说明 属性名 说明 生效时机 @getphonenumber 获取用户手机号回调 open-type=\\\"getPhoneNumber\\\"  按钮写法 接口说明 接口 说明 wx.login() 获取登录凭证(code),通过凭证进而换取用户登录态信息 auth.code2Session 登录凭证校验 参数说明

    2024年02月10日
    浏览(34)
  • 微信小程序 - 实现手机号登录--授权并获取手机号保存至本地

    微信官方文档 | 获取手机号 这是服务端的  这是我们前端获取手机号需要给接口传递的两个参数    注意: 参数一: 获取access_token需要用到小程序密钥,这个需要从 服务端获取 ,也就是需要请求后端接口获取access_token,千万不要将小程序密钥写在前端代码中, 必须 要从服

    2024年02月03日
    浏览(44)
  • uniapp实现手机号一键登录功能

    1,第一步 2,第二步 创建应用要和项目uni-appid一致。 3,第三步 4,第四步 5,第五步 6,第六步 7,第七步 8,第八步 (实现代码) 一建登录步骤到此结束,欢迎大家讨论和指导,登录弹窗本文设置的是全屏‘fullScreen’,大家可根据需求编辑,弹窗只能在手机端app才能显示。

    2024年02月16日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包