欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot實(shí)現(xiàn)返回值數(shù)據(jù)脫敏的步驟詳解

 更新時(shí)間:2023年07月14日 10:57:07   作者:月色無(wú)痕  
這篇文章主要給大家介紹一下SpringBoot實(shí)現(xiàn)返回值數(shù)據(jù)脫敏的步驟,文章通過(guò)代碼示例介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下

介紹

  • SpringBoot實(shí)現(xiàn)返回?cái)?shù)據(jù)脫敏

  • 有時(shí),敏感數(shù)據(jù)返回時(shí),需要進(jìn)行隱藏處理,但是如果一個(gè)字段一個(gè)字段的進(jìn)行硬編碼處理的話,不僅增加了工作量,而且后期需求變動(dòng)的時(shí)候,更加是地獄般的工作量變更。

  • 下面,通過(guò)身份證,姓名,密碼,手機(jī)號(hào)等等示例去演示脫敏的流程,當(dāng)然你也可以在此基礎(chǔ)上添加自己的實(shí)現(xiàn)方式

原理

  • 項(xiàng)目使用的是SpringBoot,所以需要在序列化的時(shí)候,進(jìn)行脫敏處理,springboot內(nèi)置的序列化工具為jackson
  • 通過(guò)實(shí)現(xiàn)com.fasterxml.jackson.databind.JsonSerializer進(jìn)行自定義序列化
  • 通過(guò)重寫com.fasterxml.jackson.databind.ser.ContextualSerializer.createContextual獲取自定義注解的信息

實(shí)現(xiàn)

自定義注解類

@Target(ElementType.FIELD) //作用于字段上
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside  // 表示自定義自己的注解Sensitive
@JsonSerialize(using = SensitiveInfoSerialize.class) // 該注解使用序列化的方式
public @interface Sensitive {
    SensitizedType value();
}

創(chuàng)建脫敏字段類型枚舉

public enum SensitizedType {
    /**
     * 用戶id
     */
    USER_ID,
    /**
     * 中文名
     */
    CHINESE_NAME,
    /**
     * 身份證號(hào)
     */
    ID_CARD,
    /**
     * 座機(jī)號(hào)
     */
    FIXED_PHONE,
    /**
     * 手機(jī)號(hào)
     */
    MOBILE_PHONE,
    /**
     * 地址
     */
    ADDRESS,
    /**
     * 電子郵件
     */
    EMAIL,
    /**
     * 密碼
     */
    PASSWORD,
    /**
     * 中國(guó)大陸車牌,包含普通車輛、新能源車輛
     */
    CAR_LICENSE,
    /**
     * 銀行卡
     */
    BANK_CARD,
    /**
     * IPv4地址
     */
    IPV4,
    /**
     * IPv6地址
     */
    IPV6,
    /**
     * 定義了一個(gè)first_mask的規(guī)則,只顯示第一個(gè)字符。
     */
    FIRST_MASK
}

脫敏工具類

import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.StrUtil;
/**
 * @Auther: wu
 * @Date: 2023/7/11
 * @Description: com.wu.demo.common.my_sensitive
 */
public class SensitizedUtil {
    public static String desensitized(CharSequence str, SensitizedType desensitizedType) {
        if (StrUtil.isBlank(str)) {
            return StrUtil.EMPTY;
        }
        String newStr = String.valueOf(str);
        switch (desensitizedType) {
            case USER_ID:
                newStr = String.valueOf(userId());
                break;
            case CHINESE_NAME:
                newStr = chineseName(String.valueOf(str));
                break;
            case ID_CARD:
                newStr = idCardNum(String.valueOf(str), 3, 4);
                break;
            case FIXED_PHONE:
                newStr = fixedPhone(String.valueOf(str));
                break;
            case MOBILE_PHONE:
                newStr = mobilePhone(String.valueOf(str));
                break;
            case ADDRESS:
                newStr = address(String.valueOf(str), 8);
                break;
            case EMAIL:
                newStr = email(String.valueOf(str));
                break;
            case PASSWORD:
                newStr = password(String.valueOf(str));
                break;
            case CAR_LICENSE:
                newStr = carLicense(String.valueOf(str));
                break;
            case BANK_CARD:
                newStr = bankCard(String.valueOf(str));
                break;
            case IPV4:
                newStr = ipv4(String.valueOf(str));
                break;
            case IPV6:
                newStr = ipv6(String.valueOf(str));
                break;
            case FIRST_MASK:
                newStr = firstMask(String.valueOf(str));
                break;
            default:
        }
        return newStr;
    }
    /**
     * 【用戶id】不對(duì)外提供userId
     *
     * @return 脫敏后的主鍵
     */
    public static Long userId() {
        return 0L;
    }
    /**
     * 定義了一個(gè)first_mask的規(guī)則,只顯示第一個(gè)字符。<br>
     * 脫敏前:123456789;脫敏后:1********。
     *
     * @param str 字符串
     * @return 脫敏后的字符串
     */
    public static String firstMask(String str) {
        if (StrUtil.isBlank(str)) {
            return StrUtil.EMPTY;
        }
        return StrUtil.hide(str, 1, str.length());
    }
    /**
     * 【中文姓名】只顯示第一個(gè)漢字,其他隱藏為2個(gè)星號(hào),比如:李**
     *
     * @param fullName 姓名
     * @return 脫敏后的姓名
     */
    public static String chineseName(String fullName) {
        return firstMask(fullName);
    }
    /**
     * 【身份證號(hào)】前1位 和后2位
     *
     * @param idCardNum 身份證
     * @param front     保留:前面的front位數(shù);從1開始
     * @param end       保留:后面的end位數(shù);從1開始
     * @return 脫敏后的身份證
     */
    public static String idCardNum(String idCardNum, int front, int end) {
        //身份證不能為空
        if (StrUtil.isBlank(idCardNum)) {
            return StrUtil.EMPTY;
        }
        //需要截取的長(zhǎng)度不能大于身份證號(hào)長(zhǎng)度
        if ((front + end) > idCardNum.length()) {
            return StrUtil.EMPTY;
        }
        //需要截取的不能小于0
        if (front < 0 || end < 0) {
            return StrUtil.EMPTY;
        }
        return StrUtil.hide(idCardNum, front, idCardNum.length() - end);
    }
    /**
     * 【固定電話 前四位,后兩位
     *
     * @param num 固定電話
     * @return 脫敏后的固定電話;
     */
    public static String fixedPhone(String num) {
        if (StrUtil.isBlank(num)) {
            return StrUtil.EMPTY;
        }
        return StrUtil.hide(num, 4, num.length() - 2);
    }
    /**
     * 【手機(jī)號(hào)碼】前三位,后4位,其他隱藏,比如135****2210
     *
     * @param num 移動(dòng)電話;
     * @return 脫敏后的移動(dòng)電話;
     */
    public static String mobilePhone(String num) {
        if (StrUtil.isBlank(num)) {
            return StrUtil.EMPTY;
        }
        return StrUtil.hide(num, 3, num.length() - 4);
    }
    /**
     * 【地址】只顯示到地區(qū),不顯示詳細(xì)地址,比如:北京市海淀區(qū)****
     *
     * @param address       家庭住址
     * @param sensitiveSize 敏感信息長(zhǎng)度
     * @return 脫敏后的家庭地址
     */
    public static String address(String address, int sensitiveSize) {
        if (StrUtil.isBlank(address)) {
            return StrUtil.EMPTY;
        }
        int length = address.length();
        return StrUtil.hide(address, length - sensitiveSize, length);
    }
    /**
     * 【電子郵箱】郵箱前綴僅顯示第一個(gè)字母,前綴其他隱藏,用星號(hào)代替,@及后面的地址顯示,比如:d**@126.com
     *
     * @param email 郵箱
     * @return 脫敏后的郵箱
     */
    public static String email(String email) {
        if (StrUtil.isBlank(email)) {
            return StrUtil.EMPTY;
        }
        int index = StrUtil.indexOf(email, '@');
        if (index <= 1) {
            return email;
        }
        return StrUtil.hide(email, 1, index);
    }
    /**
     * 【密碼】密碼的全部字符都用*代替,比如:******
     *
     * @param password 密碼
     * @return 脫敏后的密碼
     */
    public static String password(String password) {
        if (StrUtil.isBlank(password)) {
            return StrUtil.EMPTY;
        }
        return StrUtil.repeat('*', password.length());
    }
    /**
     * 【中國(guó)車牌】車牌中間用*代替
     * eg1:null       -》 ""
     * eg1:""         -》 ""
     * eg3:蘇D40000   -》 蘇D4***0
     * eg4:陜A12345D  -》 陜A1****D
     * eg5:京A123     -》 京A123     如果是錯(cuò)誤的車牌,不處理
     *
     * @param carLicense 完整的車牌號(hào)
     * @return 脫敏后的車牌
     */
    public static String carLicense(String carLicense) {
        if (StrUtil.isBlank(carLicense)) {
            return StrUtil.EMPTY;
        }
        // 普通車牌
        if (carLicense.length() == 7) {
            carLicense = StrUtil.hide(carLicense, 3, 6);
        } else if (carLicense.length() == 8) {
            // 新能源車牌
            carLicense = StrUtil.hide(carLicense, 3, 7);
        }
        return carLicense;
    }
    /**
     * 銀行卡號(hào)脫敏
     * eg: 1101 **** **** **** 3256
     *
     * @param bankCardNo 銀行卡號(hào)
     * @return 脫敏之后的銀行卡號(hào)
     * @since 5.6.3
     */
    public static String bankCard(String bankCardNo) {
        if (StrUtil.isBlank(bankCardNo)) {
            return bankCardNo;
        }
        bankCardNo = StrUtil.trim(bankCardNo);
        if (bankCardNo.length() < 9) {
            return bankCardNo;
        }
        final int length = bankCardNo.length();
        final int midLength = length - 8;
        final StringBuilder buf = new StringBuilder();
        buf.append(bankCardNo, 0, 4);
        for (int i = 0; i < midLength; ++i) {
            if (i % 4 == 0) {
                buf.append(CharUtil.SPACE);
            }
            buf.append('*');
        }
        buf.append(CharUtil.SPACE).append(bankCardNo, length - 4, length);
        return buf.toString();
    }
    /**
     * IPv4脫敏,如:脫敏前:192.0.2.1;脫敏后:192.*.*.*。
     *
     * @param ipv4 IPv4地址
     * @return 脫敏后的地址
     */
    public static String ipv4(String ipv4) {
        return StrUtil.subBefore(ipv4, '.', false) + ".*.*.*";
    }
    /**
     * IPv4脫敏,如:脫敏前:2001:0db8:86a3:08d3:1319:8a2e:0370:7344;脫敏后:2001:*:*:*:*:*:*:*
     *
     * @param ipv6 IPv4地址
     * @return 脫敏后的地址
     */
    public static String ipv6(String ipv6) {
        return StrUtil.subBefore(ipv6, ':', false) + ":*:*:*:*:*:*:*";
    }
}

上述枚舉類和脫敏工具類,我使用了hutool中的代碼,如果hutool滿足你的需求,可以直接把上述自定義注解類和自定義序列化類使用到的SensitizedType類直接替換為hutool中的cn.hutool.core.util.DesensitizedUtil.DesensitizedType的枚舉類,

添加自定義序列化實(shí)現(xiàn)類

public class SensitiveInfoSerialize extends JsonSerializer<String> implements ContextualSerializer {
    private SensitizedType sensitizedType;
    /**
     * 步驟一
     * 方法來(lái)源于ContextualSerializer,獲取屬性上的注解屬性,同時(shí)返回一個(gè)合適的序列化器
     */
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        // 獲取自定義注解
        Sensitive annotation = beanProperty.getAnnotation(Sensitive.class);
        // 注解不為空,且標(biāo)注的字段為String
        if(Objects.nonNull(annotation) && Objects.equals(String.class, beanProperty.getType().getRawClass())){
            this.sensitizedType = annotation.value();
            //自定義情況,返回本序列化器,將順利進(jìn)入到該類中的serialize方法中
            return this;
        }
        // 注解為空,字段不為String,尋找合適的序列化器進(jìn)行處理
        return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
    }
    /**
     * 步驟二
     * 方法來(lái)源于JsonSerializer<String>:指定返回類型為String類型,serialize()將修改后的數(shù)據(jù)返回
     */
    @Override
    public void serialize(String str, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        if(Objects.isNull(sensitizedType)){
            // 定義策略為空,返回原字符串
            jsonGenerator.writeString(str);
        }else {
            // 定義策略不為空,返回策略處理過(guò)的字符串
            jsonGenerator.writeString(SensitizedUtil.desensitized(str,sensitizedType));
        }
    }
}

測(cè)試驗(yàn)證

在需要的脫敏的實(shí)體類字段上加上相應(yīng)的注解

@Data
public class SensitiveBody {
    private String name;
    @Sensitive(SensitizedType.MOBILE_PHONE)
    private String mobile;
    @Sensitive(SensitizedType.ID_CARD)
    private String idCard;
}
    @ApiOperation(value = "脫敏測(cè)試處理")
    @GetMapping("sensitiveTest")
    public AjaxResult sensitiveTest(){
        SensitiveBody body = new SensitiveBody();
        body.setMobile("13041064026");
        body.setIdCard("411126189912355689");
        body.setName("Tom");
        return AjaxResult.success(body);
    }

到此這篇關(guān)于SpringBoot實(shí)現(xiàn)返回值數(shù)據(jù)脫敏的步驟詳解的文章就介紹到這了,更多相關(guān)SpringBoot返回值數(shù)據(jù)脫敏內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java利用ElasticSearch實(shí)現(xiàn)增刪改功能

    Java利用ElasticSearch實(shí)現(xiàn)增刪改功能

    這篇文章主要為大家詳細(xì)介紹了Java如何利用ElasticSearch實(shí)現(xiàn)增刪改功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-08-08
  • Java中的世界時(shí)區(qū)如何自動(dòng)計(jì)算及生成?

    Java中的世界時(shí)區(qū)如何自動(dòng)計(jì)算及生成?

    在?Java?中,處理時(shí)區(qū)和時(shí)間計(jì)算是一個(gè)非常常見的需求,尤其是在涉及全球應(yīng)用時(shí),Java?提供了一些強(qiáng)大的?API?來(lái)處理世界時(shí)區(qū)(如?java.time?包),下面將介紹如何基于?Java?自動(dòng)計(jì)算時(shí)區(qū)并生成相應(yīng)的時(shí)間
    2025-01-01
  • Java使用備忘錄模式實(shí)現(xiàn)過(guò)關(guān)類游戲功能詳解

    Java使用備忘錄模式實(shí)現(xiàn)過(guò)關(guān)類游戲功能詳解

    這篇文章主要介紹了Java使用備忘錄模式實(shí)現(xiàn)過(guò)關(guān)類游戲功能,結(jié)合實(shí)例形式詳細(xì)分析了java備忘錄模式的概念、原理及其在過(guò)關(guān)類游戲中的具體應(yīng)用方法,需要的朋友可以參考下
    2018-04-04
  • 完美解決SpringCloud-OpenFeign使用okhttp替換不生效問(wèn)題

    完美解決SpringCloud-OpenFeign使用okhttp替換不生效問(wèn)題

    這篇文章主要介紹了完美解決SpringCloud-OpenFeign使用okhttp替換不生效問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-02-02
  • Feign+mybatisplus搭建項(xiàng)目遇到的坑及解決

    Feign+mybatisplus搭建項(xiàng)目遇到的坑及解決

    這篇文章主要介紹了Feign+mybatisplus搭建項(xiàng)目遇到的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • SpringBoot異常處理之異常顯示的頁(yè)面問(wèn)題

    SpringBoot異常處理之異常顯示的頁(yè)面問(wèn)題

    這篇文章主要介紹了SpringBoot異常處理異常顯示的頁(yè)面的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-09-09
  • 簡(jiǎn)單了解JAVA內(nèi)存泄漏和溢出區(qū)別及聯(lián)系

    簡(jiǎn)單了解JAVA內(nèi)存泄漏和溢出區(qū)別及聯(lián)系

    這篇文章主要介紹了簡(jiǎn)單了解JAVA內(nèi)存泄漏和溢出區(qū)別及聯(lián)系,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • spring如何實(shí)現(xiàn)依賴注入DI(spring-test方式)

    spring如何實(shí)現(xiàn)依賴注入DI(spring-test方式)

    本文主要介紹如何實(shí)現(xiàn)spring 的依賴注入,并且淺顯的講述一下注入需要注意的事項(xiàng)。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java的無(wú)參構(gòu)造函數(shù)用法實(shí)例分析

    Java的無(wú)參構(gòu)造函數(shù)用法實(shí)例分析

    這篇文章主要介紹了Java的無(wú)參構(gòu)造函數(shù)用法,結(jié)合實(shí)例形式分析了java無(wú)參構(gòu)造函數(shù)基本原理、用法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下
    2019-09-09
  • 深入理解Java中觀察者模式與委托的對(duì)比

    深入理解Java中觀察者模式與委托的對(duì)比

    這篇文章主要介紹了Java中觀察者模式與委托的對(duì)比,觀察者模式:定義了一種一對(duì)多的依賴關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽某一個(gè)主題對(duì)象,委托的實(shí)現(xiàn)簡(jiǎn)單來(lái)講就是用反射來(lái)實(shí)現(xiàn)的,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-05-05

最新評(píng)論