Spring aop+反射实现电话号加密

 更新时间:2021年6月5日 15:00  点击:1553

加密算法

为什么需要加密呢?就好比战争时期特工在进行传输情报的时候,如果将情报明文直接通过某种媒介传输给同盟人员,那么一旦情报被地方截取,就会酿成大祸。如果将明文通过某种加密算法加密成杂乱无章的密文,即使被敌方截获,没有对应的解密算法,也很难识别出其中的明文。安全传输领域,加密算法是一种很常用的手段,它可以保证数据不被窃取和泄漏,还可以保证数据的完整性,不被篡改。

常见的加密算法有对称加密,非对称加密,单向加密(签名)等分类。其中对称加密算法,加密密钥和解密密钥是同一个,因此发送发和接收方都需要维护一个相同的密钥,如果密钥要修改,双方都需要同时修改。非对称加密算法中,发送发用公钥进行加密,接收方用私钥进行解密。单向加密算法是对传输的数据生成一个签名,通过这个签名来验证数据在传输过程中是否被篡改过,一般是不可逆的。

AES

  • AES 加密算法是一种对称加密算,加密密钥和解密密钥是同一个。它采用对称分组密码体制,最少支持长度为128位的加密。涉及到分组加密,padding填充,初始向量IV,密钥,四种加密模式。
  • 分组加密就是将原文分割成一段段的分别进行加密,每段分组长度为128位16个字节,如果最后一组长度不足128位,则采用padding填充模式将其补齐到128位。然后对每组进行加密,最后组成最终密文。
  • padding填充是为了解决分组后的长度不足128位的场景。填充模式也有多种不同模式,比如PKCS5, PKCS7和NOPADDING。其中PKSC5是指分组后缺少几个字节,就在后面填充几个字节的几,比如缺少2个字节,就在后面填充2个字节的2。PKCS7是指缺少几个字节,就在后面填充几个字节的0,比如缺少5个字节,就填充5个字节的0。NOPADDING模式就是不需要填充。如果最后面刚好是16个字节的16,那么解密方不知道是填充数据还是真实数据,因此会在后面再补16个字节的16来区分。
  • 初始向量IV是为了保证数据的安全性,如果我们对同一段内容进行加密后,所生成的密文应该是相同的,那么这样就很容易通过密文分析出哪些段是相同的。比如原文分组后成为ABCADE,加密后的密文是GHIGJK,那么很容易看出那两段内容是相同的。第一个分组在初始加密向量的基础上进行加密,以后的每一个分组都在前一个分组加密的结果为基础进行加密,从而保证了即使相同的原文段,也不会生成相同的密文段。
  • 密钥是加密和解密公用的一个,它一般是128位16个字节长度的随机字符串,分组后的原文都用同一个密钥进行加密。
  • 加密模式包含ECB,CBC, CFB, OFB等四种模式。ECB分别对每个分组进行加密,相同的明文会被加密成相同的密文。CBC模式会使用上一段的加密结果作为加密向量,相同的原文不会被加密成相同的密文。

MD5

MD5算法是一种不可逆的签名算法,对相同的输入通过MD5散列函数处理后,会输出相同的信息。因此MD5可以验证传输的数据是否有被篡改,但是如果窃密者对明文进行了修改后,再使用MD5算法进行散列,接收方将无法判断明文已经被修改了。一般数据库存储用户密码会将密码使用MD5进行处理。

HMAC-MD5

HMAC-MD5由一个H函数和一个密钥组成,一般我们采用的散列函数为Md5或者SHA-1。HMAC-MD5算法就是采用密钥加密+Md5信息摘要的方式形成新的密文。

AOP

众所周知,AOP(面向切面编程)是Spring一个重要特性,它将核心关注点和业务逻辑进行解耦,将业务无关的逻辑提取出来作为公共模块进行处理。它有切点,切面,连接点,通知的概念。切点就是我们可以织入切面的点,切面就是我们要织入的横切逻辑,通知包含前置通知,后置通知,返回通知,异常通知,环绕通知等。

1. 引入依赖

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.18</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.8.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.2.8.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>

2. 业主信息类、业主信息服务类

@Data
@AllArgsConstructor
public class CustomerInfo {

    private String name;

    private String phoneNum;
}

@Service
public class CustomerInfoService {

    @PhoneEncryptionForList(fields = "phoneNum", clazz = CustomerInfo.class)
    public List<CustomerInfo> listCustomerInfo() {
        return Arrays.asList(
                new CustomerInfo("小王", "15112368569"),
                new CustomerInfo("小李", "13652298565"),
                new CustomerInfo("小武", "18965653698"),
                new CustomerInfo("小天", "13192558569")
        );
    }
}

3. 电话号加密注解,电话号加密切面类

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PhoneEncryptionForList {

    /**
     * 加密字段
     *
     * @return
     */
    String[] fields();

    /**
     * 加密对象类型
     *
     * @return
     */
    Class<?> clazz();
}

@Aspect
@Component
public class PhoneEncryptionForListAspect {

    private static final int PHONE_SIZE = 11;

    @AfterReturning(value = "@annotation(com.zzq.spring.phone.encryption.PhoneEncryptionForList)", returning = "result")
    public void doEncrypt(JoinPoint joinPoint, Object result) {
        if (result == null || !(result instanceof List)) {
            System.out.println("result class type is not list, annotation is invalid");
            return;
        }

        List list = (List) result;
        if (CollectionUtils.isEmpty(list)) {
            return;
        }

        // 获取注解的属性值
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        PhoneEncryptionForList annotation = method.getAnnotation(PhoneEncryptionForList.class);
        String[] fields = annotation.fields();
        Class<?> clazz = annotation.clazz();

        for (String field : fields) {
            try {
                // 反射获取实体类加密字段相应的 set 和 get 方法
                char[] chars = field.toCharArray();
                chars[0] = (char) (chars[0] - 32);
                String setMethodName = "set" + new String(chars);
                String getMethodName = "get" + new String(chars);
                Method getMethod = clazz.getDeclaredMethod(getMethodName);
                Method setMethod = clazz.getDeclaredMethod(setMethodName, String.class);

                for (Object obj : list) {
                    doEncryptPhone(getMethod, setMethod, obj);
                }
            } catch (Exception e) {
                System.out.println(field + " encrypt exception, " + e.getMessage());
                continue;
            }
        }
    }

    private static void doEncryptPhone(Method getMethod, Method setMethod, Object obj) throws Exception {
        // 反射调用 get 方法
        String originalPhone = (String)getMethod.invoke(obj);
        if (!StringUtils.hasText(originalPhone) || originalPhone.length() != PHONE_SIZE) {
            System.out.println("phone field value is blank or formal error");
            return;
        }

        String encryptedPhone = originalPhone.replaceAll("(\\d{3})\\d{4}(\\d{4})","$1****$2");
        // 反射调用 set 方法
        setMethod.invoke(obj, encryptedPhone);
    }
}

4. 测试类

@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.zzq.spring.phone.encryption")
public class TestApplication {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(TestApplication.class);

        CustomerInfoService customerInfoService = ctx.getBean(CustomerInfoService.class);
        List<CustomerInfo> afterPhoneEncryptCustomerInfos = customerInfoService.listCustomerInfo();

        afterPhoneEncryptCustomerInfos.forEach(customerInfos -> {
            System.out.println(customerInfos);
        });
    }
}

5. 结果和总结

该加密注解只简单实现了电话号加密,注解中还可以新增一些属性扩展注解功能,比如增加加密字段格式加密规则的正则表达式的属性值,这样加密的字段类型(手机号、身份证等)和方式(中间多少位加密、首位加密)就可以根据具体需求处理。

以上就是Spring aop+反射实现电话号加密的详细内容,更多关于Spring aop电话号加密的资料请关注猪先飞其它相关文章!

[!--infotagslink--]

相关文章

  • Spring AOP 对象内部方法间的嵌套调用方式

    这篇文章主要介绍了Spring AOP 对象内部方法间的嵌套调用方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-08-29
  • 图解PHP使用Zend Guard 6.0加密方法教程

    有时为了网站安全和版权问题,会对自己写的php源码进行加密,在php加密技术上最常用的是zend公司的zend guard 加密软件,现在我们来图文讲解一下。 下面就简单说说如何...2016-11-25
  • Spring Cloud 中@FeignClient注解中的contextId属性详解

    这篇文章主要介绍了Spring Cloud 中@FeignClient注解中的contextId属性详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-25
  • Springboot如何实现Web系统License授权认证

    这篇文章主要介绍了Springboot如何实现Web系统License授权认证,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-05-28
  • 如何在Spring WebFlux的任何地方获取Request对象

    这篇文章主要介绍了如何在Spring WebFlux的任何地方获取Request对象,帮助大家更好的理解和使用springboot框架,感兴趣的朋友可以了解下...2021-01-26
  • 详解SpringCloudGateway内存泄漏问题

    这篇文章主要介绍了详解SpringCloudGateway内存泄漏问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-07-16
  • vue接口请求加密实例

    这篇文章主要介绍了vue接口请求加密实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-12
  • AES加密解密的例子小结

    关于AES加密的算法我们就不说了,这里主要给各位演示了三个关于AES算法实现的加密例子,希望本文章能给你带来帮助。 话不多说,先放上代码,一共有两个文件:AES.php(aes算...2016-11-25
  • node.JS md5加密中文与php结果不一致怎么办

    这次文章要给大家介绍的是node.JS md5加密中文与php结果不一致怎么办,不知道具体解决办法的下面跟小编一起来看看。 因项目需要,需要Node.js与PHP做接口调用,发现nod...2017-07-06
  • Spring为什么不推荐使用@Autowired注解详析

    @Autowired 注解的主要功能就是完成自动注入,使用也非常简单,但这篇文章主要给大家介绍了关于Spring为什么不推荐使用@Autowired注解的相关资料,需要的朋友可以参考下...2021-11-03
  • NODE.JS加密模块CRYPTO常用方法介绍

    使用require('crypto')调用加密模块。加密模块需要底层系统提供OpenSSL的支持。它提供了一种安全凭证的封装方式,可以用于HTTPS安全网络以及普通HTTP连接。该模块还提供了一套针对OpenSSL的hash(哈希),hmac(密钥哈希),cipher...2014-06-07
  • Springboot如何使用mybatis实现拦截SQL分页

    这篇文章主要介绍了Springboot使用mybatis实现拦截SQL分页,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-06-19
  • C#连接加密的Sqlite数据库的方法

    对数据加密分两种,一种是对数据库本身进行加密,另一种是对数据表中的数据进行加密,下面通过本文给大家介绍C#连接加密的Sqlite数据库的方法,感兴趣的朋友一起看看吧...2020-06-25
  • SpringMVC文件上传原理及实现过程解析

    这篇文章主要介绍了SpringMVC文件上传原理及实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-07-15
  • C#实现对文件进行加密解密的方法

    这篇文章主要介绍了C#实现对文件进行加密解密的方法,涉及C#加密与解密的技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • Spring Data JPA 关键字Exists的用法说明

    这篇文章主要介绍了Spring Data JPA 关键字Exists的用法说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-06-10
  • php使用异或实现的加解密的方法

    若a=b ^ c;则b=a ^ c (^是异或的意思),php在处理异或的字符时先把字符转化为二进制的ascii值,对这些值进行异或,获取结果后在将ascii值转化为字符...2013-09-26
  • tomcat启动完成执行 某个方法 定时任务(Spring)操作

    这篇文章主要介绍了tomcat启动完成执行 某个方法 定时任务(Spring)操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-25
  • 使用Maven 搭建 Spring MVC 本地部署Tomcat的详细教程

    这篇文章主要介绍了使用Maven 搭建 Spring MVC 本地部署Tomcat,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-08-16
  • go语言使用RC4加密的方法

    这篇文章主要介绍了go语言使用RC4加密的方法,实例分析了RC4加密的技巧与实现方法,具有一定参考借鉴价值,需要的朋友可以参考下...2020-05-07