{"id":20482935,"url":"https://github.com/lzhpo/sensitive-spring-boot-starter","last_synced_at":"2025-04-07T07:04:29.940Z","repository":{"id":45794981,"uuid":"481402537","full_name":"lzhpo/sensitive-spring-boot-starter","owner":"lzhpo","description":"一款强大的数据脱敏插件，支持多种脱敏策略（中文姓名、身份证号、固定电话、手机号码、地址、电子邮箱、密码、车牌号、银行卡号、AES/DES/BASE64/RSA算法加密...），支持自定义脱敏策略，支持自定义脱敏替换符，支持多层嵌套属性脱敏，支持在Controller上使用注解跳过脱敏...","archived":false,"fork":false,"pushed_at":"2024-11-29T16:11:10.000Z","size":749,"stargazers_count":87,"open_issues_count":0,"forks_count":21,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-31T06:07:04.434Z","etag":null,"topics":["sensitive","spring","spring-boot"],"latest_commit_sha":null,"homepage":"http://www.lzhpo.com","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lzhpo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-04-13T23:23:17.000Z","updated_at":"2025-03-22T09:21:14.000Z","dependencies_parsed_at":"2023-07-13T17:59:11.556Z","dependency_job_id":"b292d61b-362c-4781-827f-6330f80f1664","html_url":"https://github.com/lzhpo/sensitive-spring-boot-starter","commit_stats":null,"previous_names":["lzhpo/panda-sensitive"],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lzhpo%2Fsensitive-spring-boot-starter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lzhpo%2Fsensitive-spring-boot-starter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lzhpo%2Fsensitive-spring-boot-starter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lzhpo%2Fsensitive-spring-boot-starter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lzhpo","download_url":"https://codeload.github.com/lzhpo/sensitive-spring-boot-starter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247608150,"owners_count":20965952,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["sensitive","spring","spring-boot"],"created_at":"2024-11-15T16:15:17.246Z","updated_at":"2025-04-07T07:04:29.919Z","avatar_url":"https://github.com/lzhpo.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"![](https://img.shields.io/badge/JDK-1.8+-success.svg)\n![](https://maven-badges.herokuapp.com/maven-central/com.lzhpo/sensitive-spring-boot-starter/badge.svg?color=blueviolet)\n![](https://img.shields.io/:license-Apache2-orange.svg)\n[![Style check](https://github.com/lzhpo/sensitive-spring-boot-starter/actions/workflows/style-check.yml/badge.svg)](https://github.com/lzhpo/sensitive-spring-boot-starter/actions/workflows/style-check.yml)\n[![Codacy Badge](https://app.codacy.com/project/badge/Grade/e42fca0b3faf4daeb7d2f9e32f396376)](https://www.codacy.com/gh/lzhpo/sensitive-spring-boot-starter/dashboard?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=lzhpo/sensitive-spring-boot-starter\u0026amp;utm_campaign=Badge_Grade)\n\n## 开源地址\n\n- GitHub：[https://github.com/lzhpo/sensitive-spring-boot-starter](https://github.com/lzhpo/sensitive-spring-boot-starter)\n- Gitee：[https://gitee.com/lzhpo/sensitive-spring-boot-starter](https://gitee.com/lzhpo/sensitive-spring-boot-starter)\n\n## 如何使用？\n\n*sensitive-spring-boot-starter也支持SpringBoot3*\n\n\u003e 3.0.0及以上版本的sensitive-spring-boot-starter只针对使用SpringBoot3用户，SpringBoot2用户请使用低于3.0.0版本的sensitive-spring-boot-starter，两者功能不受影响，均会同步更新！\n\n### 1.导入依赖\n\n\u003e 依赖已发布至Maven中央仓库，可直接引入依赖。\n\n- Maven：\n\n  ```xml\n  \u003cdependency\u003e\n    \u003cgroupId\u003ecom.lzhpo\u003c/groupId\u003e\n    \u003cartifactId\u003esensitive-spring-boot-starter\u003c/artifactId\u003e\n    \u003cversion\u003e${latest-version}\u003c/version\u003e\n  \u003c/dependency\u003e\n  ```\n- Gradle:\n  ```groovy\n  implementation 'com.lzhpo:sensitive-spring-boot-starter:${latest-version}'\n  ```\n\n### 2.实体类字段上使用`@Sensitive`注解配置脱敏规则\n\n`@Sensitive`注解说明：\n- `strategy`：脱敏策略，支持21种脱敏策略。\n\n#### 2.1.支持的脱敏策略\n\n*以下数据均为随意构造的测试数据，如有相同，纯属巧合。*\n\n##### 2.1.1 中文姓名\n\n只显示第一个汉字，其他隐藏为2个星号。\n\n```java\n@Sensitive(strategy = SensitiveStrategy.CHINESE_NAME)\nprivate String name;\n```\n比如：`刘子豪`脱敏之后为`刘**`。\n\n##### 2.1.2 身份证号\n\n保留前1位和后2位。\n\n```java\n@Sensitive(strategy = SensitiveStrategy.ID_CARD)\nprivate String idCard;\n```\n比如：`530321199204074611`脱敏之后为`5***************11`。\n\n##### 2.1.3 固定电话\n\n保留前4位和后2位。\n\n```java\n@Sensitive(strategy = SensitiveStrategy.FIXED_PHONE)\nprivate String fixedPhone;\n```\n比如：`01086551122`脱敏之后为`0108*****22`。\n\n##### 2.1.4 手机号码\n\n保留前3位和后4位。\n\n```java\n@Sensitive(strategy = SensitiveStrategy.MOBILE_PHONE)\nprivate String mobilePhone;\n```\n比如：`13248765917`脱敏之后为`132****5917`。\n\n##### 2.1.5 地址\n\n只显示到地区，不显示详细地址，地址长度减去8即为前缀保留的长度，后缀均用星号代替。\n\n```java\n@Sensitive(strategy = SensitiveStrategy.ADDRESS)\nprivate String address;\n```\n比如：`广州市天河区幸福小区102号`脱敏之后为`广州市天河区********`。\n\n##### 2.1.6 电子邮箱\n\n邮箱前缀仅显示第一个字母，前缀其他隐藏，用星号代替，@及后面的地址显示。\n\n```java\n@Sensitive(strategy = SensitiveStrategy.EMAIL)\nprivate String email;\n```\n比如：`example@gmail.com`脱敏之后为`e******@gmail.com`。\n\n##### 2.1.7 密码\n\n全部字符都用星号`*`代替。\n\n```java\n@Sensitive(strategy = SensitiveStrategy.PASSWORD)\nprivate String password;\n```\n比如：`123456`脱敏之后为`******`。\n\n##### 2.1.8 车牌号\n\n车牌中间用星号`*`代替。\n\n```java\n@Sensitive(strategy = SensitiveStrategy.CAR_LICENSE)\nprivate String carLicense;\n```\n比如：`粤A66666`脱敏之后为`粤A6***6`。\n\n##### 2.1.9 银行卡号\n\n保留前4位和后4位，中间的使用星号`*`代替，且中间的从第1位起，每隔4位添加一个空格用来美化。\n\n```java\n@Sensitive(strategy = SensitiveStrategy.BANK_CARD)\nprivate String bankCard;\n```\n例如：`9988002866797031`脱敏之后为`9988 **** **** 7031`。\n\n##### 2.2.0 IPV4地址\n\nIPV4地址脱敏。\n\n```java\n@Sensitive(strategy = SensitiveStrategy.IPV4)\nprivate String ipv4;\n```\n\n例如：`192.0.2.1`脱敏之后为`192.*.*.*`。\n\n##### 2.2.1 IPV6地址\n\nIPV6地址脱敏。\n\n```java\n@Sensitive(strategy = SensitiveStrategy.IPV6)\nprivate String ipv6;\n```\n\n例如：`2001:0db8:86a3:08d3:1319:8a2e:0370:7344`脱敏之后为`2001:*:*:*:*:*:*:*`。\n\n##### 2.2.2 Base64加密\n\n```java\n@Sensitive(strategy = SensitiveStrategy.BASE64)\nprivate String base64;\n```\n\n##### 2.2.3 AES加密\n\n```java\n@Sensitive(strategy = SensitiveStrategy.AES)\nprivate String aes;\n```\n\n需要配置 AES 加密的 key，例如：\n```yaml\nsensitive:\n  encrypt:\n    aes:\n      key: \"1234567890123456\"\n```\n\n##### 2.2.4 DES加密\n\n```java\n@Sensitive(strategy = SensitiveStrategy.DES)\nprivate String des;\n```\n\n需要配置 DES 加密的 key，例如：\n```yaml\nsensitive:\n  encrypt:\n    des:\n      key: \"12345678\"\n```\n\n##### 2.2.5 RSA加密\n\n```java\n@Sensitive(strategy = SensitiveStrategy.RSA)\nprivate String rsa;\n```\n\n需要配置 RSA 加密的 private key 和 public key，例如：\n```yaml\nsensitive:\n  encrypt:\n    rsa:\n      private-key: \"MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANyhI/9e5evQyzRLVsUmbQesdRl7fXu9ZAl6lZqVyL+ypf6FmQouH89OTEv/JjmybuAha9zsYwNAKSobSRATaqYSCvdwoPRgUFRFfq6ed61kpO5+D+T/X3v85JmXIngkieCe9n5b5KT3XNtHFBXVsZ3/onWEYZRhFMTsMsKkvijBAgMBAAECgYAKV2fEbC5vAp0JvRfKuym8ZLgi6wPHWWnfW154jdmIab9n2huBq4aMbSU8oS+pn+xcR1jC1NYxxG/BhGCk9yIGIzE/57tggjibNpiqC/uS12SiaJPz9oqOVJPI+l5uf9xqdytzvNJe6AGMViZdS+nnQRZfdDrs5cgghv7lx+kjiQJBAOQWmEJukHaIUXvW8ZWNekIgb8/Frq7gNvRaeqjqpZMqUIXXDj80eODGsNjIUwwEdlFX4//C7udmLfWfhyOq1bkCQQD3oOGP8rjIkouhbJldaILeuaN3ee3v3dtsmLM8epC9HH3EcFBD2O+l60wCa67uM/ArPn3XjL/lidqnVAJHPG9JAkEAumz1WicAkMFuyGew4enXKcFVYl9THcBJaoOhifrwBk8prZtPG74Jpr7/wNBLgKENDANoaZ2soxnTKtWPIUn6kQJAAmcxSTBV0rx5VmuzYVCuVHMAvxwTzwwcIQWqV5/o36zzG4Drhn0Idle+ORfKbs1aO1Ez72+SPSwFTzJlg0N24QJATQu2dlhbm87uGh0fUHpV6Nw6lf/mBMek1stC8PQXB0MtNPeYd+Ul45zfc+k5mIWUHwt47To5uAo2ywsCSdWBCw==\"\n      public-key: \"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcoSP/XuXr0Ms0S1bFJm0HrHUZe317vWQJepWalci/sqX+hZkKLh/PTkxL/yY5sm7gIWvc7GMDQCkqG0kQE2qmEgr3cKD0YFBURX6unnetZKTufg/k/197/OSZlyJ4JIngnvZ+W+Sk91zbRxQV1bGd/6J1hGGUYRTE7DLCpL4owQIDAQAB\"\n```\n\n关于 private key 和 public key 的生成方式：\n```java\nKeyPair keyPair = SecureUtil.generateKeyPair(\"RSA\");\n\nString privateKey = Base64.encode(keyPair.getPrivate().getEncoded());\nSystem.out.println(\"privateKey: \" + privateKey);\n\nString publicKey = Base64.encode(keyPair.getPublic().getEncoded());\nSystem.out.println(\"publicKey: \" + publicKey);\n```\n\n##### 2.2.6 只保留首字符\n\n```java\n@Sensitive(strategy = SensitiveStrategy.FIRST_MASK)\nprivate String firstMask;\n```\n\n例如：`123456789`脱敏之后为`1********`。\n\n##### 2.2.7 清空为null\n\n```java\n@Sensitive(strategy = SensitiveStrategy.CLEAR_TO_NULL)\nprivate String clearToNull;\n```\n\n##### 2.2.8 清空为空字符串\n\n```java\n@Sensitive(strategy = SensitiveStrategy.CLEAR_TO_NULL)\nprivate String clearToNull;\n```\n\n##### 2.2.9 自定义脱敏策略\n\n当前支持三种风格的自定义脱敏策略：\n1. 保留前后缀脱敏策略。\n2. 敏感字符脱敏策略。\n3. Handler脱敏策略。\n\n###### 2.2.1.1 保留前后缀脱敏策略\n\n使用`@Sensitive(strategy = SensitiveStrategy.CUSTOMIZE_KEEP_LENGTH)`配合`@SensitiveKeepLength`一起使用。\n\n`@SensitiveFilterWords`注解：\n- `preKeep`是字符串前置保留字符个数。\n- `postKeep`是字符串后置保留字符个数。\n\n举个例子：`name`前后都只保留1个字符。\n\n```java\n@Sensitive(strategy = SensitiveStrategy.CUSTOMIZE_KEEP_LENGTH)\n@SensitiveKeepLength(preKeep = 1, postKeep = 1)\nprivate String name;\n```\n\n如果`name`为`1234`，脱敏之后就是`1**4`。\n\n###### 2.2.1.2 敏感字符脱敏策略\n\n使用`@Sensitive(strategy = SensitiveStrategy.CUSTOMIZE_FILTER_WORDS)`配合`@SensitiveFilterWords`一起使用。\n\n`@SensitiveFilterWords`注解：定义敏感字符。\n\n举个例子：脏话关键字脱敏。\n\n```java\n@Sensitive(strategy = SensitiveStrategy.CUSTOMIZE_FILTER_WORDS)\n@SensitiveFilterWords({\"他妈的\", \"去你大爷\", \"卧槽\", \"草泥马\", \"废物\"})\nprivate String description;\n```\n\n如果`description`的值为`卧槽，他妈的，我去你大爷的，草泥马`，脱敏之后就是`**，***，我****的，***`。\n\n###### 2.2.1.3 Handler脱敏策略\n\nHandler脱敏策略完全由开发者进行处理，不受`@Sensitive`注解上的`replacer`脱敏替换符影响。\n\n使用`@Sensitive(strategy = SensitiveStrategy.CUSTOMIZE_HANDLER)`配合`@SensitiveHandler`一起使用。\n\n`@SensitiveHandler`注解：表示处理脱敏的Handler。\n\n例如：将`name`字段都设置为`@#@`。\n\n```java\n@Sensitive(strategy = SensitiveStrategy.CUSTOMIZE_HANDLER)\n@SensitiveHandler(FaceCustomizeSensitiveHandler.class)\nprivate String name;\n```\n\n```java\npublic class FaceCustomizeSensitiveHandler implements CustomizeSensitiveHandler {\n\n  @Override\n  public String customize(SensitiveWrapper sensitiveWrapper) {\n    // 字段\n    Field field = sensitiveWrapper.getField();\n    // 字段归属的对象\n    Class\u003c?\u003e objectClass = field.getDeclaringClass();\n    // 字段上的注解\n    Annotation[] annotations = field.getAnnotations();\n    // 字段值\n    String fieldValue = sensitiveWrapper.getFieldValue();\n    // 注解信息\n    Sensitive sensitive = sensitiveWrapper.getSensitive();\n    return \"@#@\";\n  }\n}\n```\n\n可以看到，提供了含有`@Sensitive`注解的字段、字段值、字段归属的对象、注解的信息等等供开发者定制。\n\n### 3.使用`@IgnoreSensitive`注解标注在controller上可忽略脱敏\n\n如果实体类标注了`@Sensitive`脱敏，被多个接口共用的，接口A要脱敏，但是接口B不需要脱敏，就可以使用`@IgnoreSensitive`注解忽略脱敏，同时也支持忽略指定字段脱敏。\n\n#### 1.在Controller类上使用`@IgnoreSensitive`表示此类下所有接口都忽略脱敏\n\n此controller下的所有接口都将忽略脱敏。\n\n```java\n@RestController\n@IgnoreSensitive\n@RequestMapping(\"/ignore\")\npublic class NoSensitiveController {\n\n  @GetMapping(\"sample3\")\n  public ResponseEntity\u003cSampleJavaBean\u003e sample3() {\n    return ResponseEntity.ok(SampleJavaBeanMock.sampleJavaBean());\n  }\n\n  @GetMapping(\"sample4\")\n  public ResponseEntity\u003cSampleJavaBean\u003e sample4() {\n    return ResponseEntity.ok(SampleJavaBeanMock.sampleJavaBean());\n  }\n}\n```\n\n#### 2.在Controller的方法中使用`@IgnoreSensitive`表示此接口忽略脱敏\n\n```java\n@RestController\n@RequestMapping(\"/\")\npublic class SensitiveController {\n\n  @GetMapping(\"sample1\")\n  public ResponseEntity\u003cSampleJavaBean\u003e sample1() {\n    return ResponseEntity.ok(SampleJavaBeanMock.sampleJavaBean());\n  }\n\n  @IgnoreSensitive\n  @GetMapping(\"ignore/sample2\")\n  public ResponseEntity\u003cSampleJavaBean\u003e sample2() {\n    return ResponseEntity.ok(SampleJavaBeanMock.sampleJavaBean());\n  }\n}\n```\n\nsample2将忽略`SampleJavaBean`对象的字段脱敏，sample1不影响。\n\n#### 3.在Controller的类或方法中使用`@IgnoreSensitive`忽略指定字段脱敏\n\n示例：忽略脱敏`SampleJavaBean`中的`name`和`email`字段的脱敏。\n```java\n@RestController\n@RequestMapping(\"/\")\npublic class SensitiveController {\n\n  @IgnoreSensitive({\"name\", \"email\"})\n  @GetMapping(\"ignore/sample\")\n  public ResponseEntity\u003cSampleJavaBean\u003e sample() {\n    return ResponseEntity.ok(SampleJavaBeanMock.sampleJavaBean());\n  }\n}\n```\n\n## 注意事项\n\n### 1.有关单独使用`@Builder`/`@SuperBuilder`注解、实体类多层嵌套问题\n\n需要数据脱敏的实体类以及嵌套类都应提供对应成员变量的get方法，否则JSON组件无法获取到嵌套的成员变量进行脱敏！\n\n- 错误示范：嵌套对象单独使用一个`@Builder`/`@SuperBuilder`\n\n  ![](./docs/images/单独使用@Builder注解问题.png)\n\n- **正确示范**：如果需要使用到`@Builder`/`@SuperBuilder`，那么需要配合`@Data`或`@Getter`一起使用。\n  \n  例如：\n  ```java\n  @Data\n  @Builder\n  @NoArgsConstructor\n  @AllArgsConstructor\n  public class SensitiveEntity {\n  \n    @Sensitive(strategy = SensitiveStrategy.CHINESE_NAME)\n    private String name;\n  \n    @Sensitive(strategy = SensitiveStrategy.ID_CARD)\n    private String idCard;\n  }\n  ```\n\n### 2.将默认的Jackson切换为FastJson（不推荐）\n\n1. 加入FastJson依赖（支持FastJson1和FastJson2）：\n    ```xml\n    \u003cdependency\u003e\n      \u003cgroupId\u003ecom.alibaba\u003c/groupId\u003e\n      \u003cartifactId\u003efastjson\u003c/artifactId\u003e\n      \u003cversion\u003e1.x.x/2.x.x\u003c/version\u003e\n    \u003c/dependency\u003e\n    ```\n2. 将`FastJsonHttpMessageConverter`声明为Bean即可，`sensitive-spring-boot-starter`会自动注入相关逻辑。\n    ```java\n    @Bean\n    public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {\n      return new FastJsonHttpMessageConverter();\n    }\n    ```\n\n### 3.关闭此数据脱敏功能\n\n移除此maven依赖即可\n\n## 微信公众号\n\n\u003cimg src=\"./docs/images/WeChat-MP.png\" width=\"453\" height=\"150\" alt=\"会打篮球的程序猿\"\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flzhpo%2Fsensitive-spring-boot-starter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flzhpo%2Fsensitive-spring-boot-starter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flzhpo%2Fsensitive-spring-boot-starter/lists"}