springboot+jackson+Hutool 脱敏注解

1 实现

脱敏注解:

import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.test.desensitize.DesensitizeJsonSerializer;
import com.test.desensitize.enums.DesensitizeStrategy;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * <pre>
 * 脱敏注解,标注在属性上
 * </pre>
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonSerialize(using = DesensitizeJsonSerializer.class)
public @interface Desensitize {
    /**
     * 脱敏策略
     */
    DesensitizeStrategy strategy();
}

脱敏策略枚举类:

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.util.Function;

/**
 * <pre>
 * 脱敏策略枚举类,针对不同的数据定制特定的脱敏策略
 * </pre>
 */
public enum DesensitizeStrategy {
    /**
     * 用户名,只显示第一个字,例如: 张三->张* 张三丰->张**
     */
    USERNAME(s -> StrUtil.isBlank(s) ? "" : StrUtil.hide(s, 1, s.length())),
    /**
     * 身份证,显示前四位和后两位,例如:1002************23
     */
    ID_CARD(s -> StrUtil.isBlank(s) ? "" : StrUtil.hide(s, 4, s.length() - 2)),
    /**
     * 手机号,显示前四位和后四位,例如:
     */
    PHONE(s -> StrUtil.isBlank(s) ? "" : StrUtil.hide(s, 3, s.length() - 4)),
    /**
     * 密码,全部隐藏,只显示位数
     */
    PASSWORD(s -> StrUtil.isBlank(s) ? "" : StrUtil.repeat('*', s.length())),
    /**
     * 邮箱,隐藏第一位和@中间内容,例如:1*********@qq.com
     */
    EMAIL(s -> {
        if (StrUtil.isBlank(s)) {
            return "";
        } else {
            int index = StrUtil.indexOf(s, '@');
            return index <= 1 ? s : StrUtil.hide(s, 1, index);
        }
    });

    private final Function<String, String> desensitize;

    DesensitizeStrategy(Function<String, String> desensitize) {
        this.desensitize = desensitize;
    }

    public Function<String, String> desensitize() {
        return desensitize;
    }
}

核心代码:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.test.desensitize.annotation.Desensitize;
import com.test.desensitize.enums.DesensitizeStrategy;
import java.io.IOException;
import java.util.Objects;

/**
 * <pre>
 * 序列化注解自定义实现
 * JsonSerializer<String>:指定String类型,serialize()方法用于将修改后的数据载入
 * Jackson使用ContextualSerializer在序列化时获取字段注解的属性
 * </pre>
 */
public class DesensitizeJsonSerializer extends JsonSerializer<String> implements ContextualSerializer {

    private DesensitizeStrategy strategy;

    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeString(strategy.desensitize().apply(value));
    }

    /**
     * 获取属性上的注解属性
     */
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        Desensitize annotation = property.getAnnotation(Desensitize.class);
        // 只针对String类型属性进行脱敏
        if (Objects.nonNull(annotation)&&Objects.equals(String.class, property.getType().getRawClass())) {
            this.strategy = annotation.strategy();
            return this;
        }
        return prov.findValueSerializer(property.getType(), property);
    }

}

2 使用场景及描述

使用场景:需要脱敏数据的时候
以下是目前提供的几种类型的脱敏策略及说明,使用时可根据脱敏策略或脱敏效果,进行选择。

脱敏策略脱敏效果示例
用户名(姓名)只显示第一个字张三–>张*
张三丰–>张**
身份证号显示前四位和后两位1002************23
手机号显示前三位和后四位139****2312
密码全部隐藏,只显示位数******
邮箱隐藏第一位和@中间内容1*********@qq.com

3 使用方法

3.1 添加注解@Desensitize

在需要进行脱敏的字段上添加@Desensitize注解,并选择具体的脱敏策略。示例如下:

@Data
public class PersonVo {
    /**
     * 真实姓名  只显示第一个字,例如: 张三->张* 张三丰->张**
     */
    @Desensitize(strategy = DesensitizeStrategy.USERNAME)
    private String realName;
    
    /**
     * 密码 全部隐藏,只显示位数
     */
    @Desensitize(strategy = DesensitizeStrategy.PASSWORD)
    private String password;
    
    /**
     * 电话号码  显示前三位和后四位,例如:139****2342
     */
    @Desensitize(strategy = DesensitizeStrategy.PHONE)
    private String phoneNumber;
    
    /**
     * 身份证号码  显示前四位和后两位,例如:4102************23
     */
    @Desensitize(strategy = DesensitizeStrategy.ID_CARD)
    private String idCard;

    /**
     * 邮箱 隐藏第一位和@中间内容,例如:1*********@qq.com
     */
    @Desensitize(strategy = DesensitizeStrategy.EMAIL)
    private String email;

}

3.2 脱敏结果

脱敏前数据:

    {
		"realName": "张三",
		"password": "123456789",
		"phoneNumber": "13901010234",
		"idCard": "100103199603282410",
		"email": "1234567.qq.com"
	}

脱敏后数据:

    {
		"realName": "张*",
		"password": "*********",
		"phoneNumber": "139****0234",
		"idCard": "1001************10",
		"email": "1******@qq.com"
	}
  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这个框架整合可以分为以下几个步骤: 1. 集成 Spring Boot:在 pom.xml 文件中添加 Spring Boot 依赖,创建 Spring Boot 启动类。 2. 集成 MyBatis Plus:在 pom.xml 文件中添加 MyBatis Plus 依赖,配置数据源和 MyBatis Plus 相关配置。 3. 集成 Shiro:在 pom.xml 文件中添加 Shiro 依赖,创建 Shiro 配置类,配置 Shiro 的 Realm 和 SecurityManager。 4. 集成 JWT:在 pom.xml 文件中添加 jjwt 依赖,创建 JWT 工具类,用于生成和解析 JWT。 下面是一个简单的示例代码,你可以根据你的实际需求进行调整: 1. pom.xml 文件中添加依赖: ```xml <!-- Spring Boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- MyBatis Plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis-plus.version}</version> </dependency> <!-- Shiro --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>${shiro.version}</version> </dependency> <!-- jjwt --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>${jjwt.version}</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>${jjwt.version}</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>${jjwt.version}</version> <scope>runtime</scope> </dependency> ``` 2. 创建 Spring Boot 启动类: ```java @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` 3. 配置 MyBatis Plus: ```java @Configuration @MapperScan("com.example.mapper") public class MyBatisPlusConfig { @Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); } } ``` 4. 配置 Shiro: ```java @Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean(); shiroFilter.setSecurityManager(securityManager); shiroFilter.setUnauthorizedUrl("/401"); Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/login", "anon"); filterChainDefinitionMap.put("/401", "anon"); filterChainDefinitionMap.put("/**", "jwt"); shiroFilter.setFilterChainDefinitionMap(filterChainDefinitionMap); Map<String, Filter> filters = new LinkedHashMap<>(); filters.put("jwt", new JwtFilter()); shiroFilter.setFilters(filters); return shiroFilter; } @Bean public DefaultWebSecurityManager securityManager(Realm realm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(realm); return securityManager; } @Bean public Realm realm() { return new UserRealm(); } } ``` 5. 创建 JWT 工具类: ```java public class JwtUtil { private static final String SECRET_KEY = "your_secret_key"; private static final long EXPIRATION_TIME = 3600_000; // 1 hour public static String generateToken(String username) { Date now = new Date(); Date expiration = new Date(now.getTime() + EXPIRATION_TIME); return Jwts.builder() .setSubject(username) .setIssuedAt(now) .setExpiration(expiration) .signWith(SignatureAlgorithm.HS512, SECRET_KEY) .compact(); } public static String getUsernameFromToken(String token) { Claims claims = Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(token) .getBody(); return claims.getSubject(); } public static boolean validateToken(String token) { try { Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token); return true; } catch (JwtException e) { return false; } } } ``` 6. 创建 JwtFilter: ```java public class JwtFilter extends AuthenticatingFilter { @Override protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) { HttpServletRequest request = (HttpServletRequest) servletRequest; String token = request.getHeader("Authorization"); if (StringUtils.isBlank(token)) { return null; } return new JwtToken(token); } @Override protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception { HttpServletResponse response = (HttpServletResponse) servletResponse; response.setCharacterEncoding("UTF-8"); response.setContentType("application/json; charset=utf-8"); response.setStatus(HttpStatus.UNAUTHORIZED.value()); response.getWriter().write("{\"code\":401,\"message\":\"未登录或登录已过期,请重新登录\"}"); return false; } @Override protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception { HttpServletRequest request = (HttpServletRequest) servletRequest; String token = request.getHeader("Authorization"); if (StringUtils.isBlank(token)) { return false; } return JwtUtil.validateToken(token); } } ``` 7. 创建 JwtToken: ```java public class JwtToken implements AuthenticationToken { private final String token; public JwtToken(String token) { this.token = token; } @Override public Object getPrincipal() { return JwtUtil.getUsernameFromToken(token); } @Override public Object getCredentials() { return token; } } ``` 8. 创建 UserRealm: ```java public class UserRealm extends AuthorizingRealm { @Autowired private UserService userService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { return null; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { String username = (String) authenticationToken.getPrincipal(); User user = userService.getByUsername(username); if (user == null) { throw new UnknownAccountException("账号不存在"); } return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName()); } } ``` 这样,简单的 Spring Boot + Shiro + JWT + MyBatis Plus 整合就完成了。你可以根据具体的需求,对代码进行修改和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值