Java如何配置白名单 java白名单如何实现

您所在的位置:网站首页 如何比对名单 Java如何配置白名单 java白名单如何实现

Java如何配置白名单 java白名单如何实现

2024-04-07 13:50| 来源: 网络整理| 查看: 265

自定义注解+拦截器完成接口IP白名单功能

从JDK5.0开始Java就增加了对元数据(MateData)的访问支持也就是注解Annotation。就目前而言注解是一种趋势,一定程度上可以说:框架 = 注解 + 反射 + 设计模式。注解其实就是给代码做特殊标记,这些标记信息可以在编译、类加载、运行时被读取到并执行相应的处理。言外之意注解允许开发者在不改变原有的逻辑、代码的情况下,在源文件中嵌入一些补充信息,增强程序的功能。例如配置应用程序的切面信息!处理接口方法的日志、安全、缓存、事务等一系列前置逻辑。

1、回顾JavaSE注解1.1、注解的使用示例

注解可以像修饰符一样被使用,可以用于修饰包、类、构造器、方法、成员变量、参数、局部变量等。

例如常见的注解使用方式有:

1、生成文档相关的注解

/* @author 标明开发该类模块的作者,多个作者之间使用,分割 @version 标明该类模块的版本 @see 参考转向,也就是相关主题 @since 从哪个版本开始增加的 @param 对方法中某参数的说明,如果没有参数就不能写 @return 对方法返回值的说明,如果方法的返回值类型是void就不能写 @exception 对方法可能抛出的异常进行说明 ,如果方法没有用throws显式抛出的异常就不能写 其中: @param @return 和 @exception 这三个标记都是只用于方法的。 @param的格式要求:@param 形参名 形参类型 形参说明 @return 的格式要求:@return 返回值类型 返回值说明 @exception的格式要求:@exception 异常类型 异常说明 @param和@exception可以并列多个 */ /** * @description: * @author: laizhenghua * @date: 2022/5/5 17:37 */ public class Test { /** * 主程序 * @param args String[] 命令行参数 */ public static void main(String[] args) { } }

2、JDK内置的三个基本注解

@Override:用于修饰方法,表示一个方法声明打算重写超类中的另一个方法声明。 @Deprecated:用于修饰方法、属性、类。表示不鼓励开发者使用这样的元素,通常是因为它很危险或者存在更好的选择。 @SuppressWarnings:抑制编译是的警告信息。public class Test { public static void main(String[] args) { @SuppressWarnings(value = "unused") // 定义的变量没有使用 使编译器没有提示 int a = 10; } }

3、代替配置文件的功能

以上配置就可以使用@Transactional注解代替

/* spring框架中关于 事务 的管理 */ public class AnnotationTest { @Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED, readOnly = false, timeout = 3) public void buyBook(String username, String isbn){ //1.查询书的单价 int price = bookShopDao.findBookPriceByIsbn(isbn); //2. 更新库存 bookShopDao.updateBookStock(isbn); //3. 更新用户的余额 bookShopDao.updateUserAccount(username, price); } }

等等,在JavaEE中注解才被大量使用,占据了更重要的角色,代替了JavaEE旧版中所遗留的冗余代码和繁琐的XML配置等。

1.2、元注解

在了解如何自定义注解时,我们还要先了解元注解。元注解就是对现有的注解进行解释说明的注解。JDK5.0也提供了4个标准的元注解(Meta-Annotation),分别是:

@Retention:指定所修饰的注解的生命周期。例如可以配置SOURCE / CLASS / RUNTIME 。只有声明为RUNTIME生命周期的注解,才能通过反射获取 @Target:用于修饰注解的使用范围(修饰注解可用在类、属性、方法等那些程序元素) @Documented:所修饰的注解在被javadoc解析时,保留下来 @Inherited:被它修饰的注解将具有继承性

1、@Retention的使用

/* @Retention: 只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 的生命 周期, @Rentention 包含一个 RetentionPolicy 类型的成员变量, 使用 @Rentention 时必须为该 value 成员变量指定值: 1 RetentionPolicy.SOURCE:在源文件中有效(即源文件保留),编译器直接丢弃这种策略的 注释 2 RetentionPolicy.CLASS:在class文件中有效(即class保留) , 当运行 Java 程序时, JVM 不会保留注解。 这是默认值 3 RetentionPolicy.RUNTIME:在运行时有效(即运行时保留),当运行 Java 程序时, JVM 会 保留注释。程序可以通过反射获取该注释 */ public enum RetentionPolicy { SOURCE, CLASS, RUNTIME } @Retention(RetentionPolicy.SOURCE) @interface MyAnnotation1{ } @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation2{ }

Java如何配置白名单 java白名单如何实现_java

2、@Target的使用

取值类型 / ElementType

描述

CONSTRUCTOR

用于修饰构造器

LIELD

用于修饰域

LOCAL_VARIABLE

用于修饰局部变量

METHOD

用于修饰方法

PACKAGE

用于修饰包

PARAMETER

用户修饰参数

TYPE

用于描述类、接口、注解类型或enum

/** * @description: IP白名单注解 * @author: laizhenghua * @date: 2022/5/15 11:08 */ @Target({ElementType.METHOD}) // 指定注解可以用在什么地方 @Retention(RetentionPolicy.RUNTIME) // 指定运行时有效 public @interface IPWhiteList { }1.3、自定义注解

前面知识了解后,自定义注解也很简单

/* 自定义注解: 1 注解声明为 @interface 2 自定义注解自动继承了java.lang.annotation.Annotation接口 3 Annotation 的成员变量在 Annotation 定义中以无参数方法的形式来声明。其 方法名和返回值定义了该成员的名字和类型。我们称为配置参数。类型只能 是八种基本数据类型、String类型、Class类型、enum类型、Annotation类型、 以上所有类型的数组。 4 可以在定义 Annotation 的成员变量时为其指定初始值, 指定成员变量的初始 值可使用 default 关键字 5 如果只有一个参数成员,建议使用参数名为value 6 如果定义的注解含有配置参数,那么使用时必须指定参数值,除非它有默认 值。格式是 参数名 = 参数值 ,如果只有一个参数成员,且名称为value, 可以省略 value= 7 没有成员定义的 Annotation 称为标记; 包含成员变量的 Annotation 称为元数 据 Annotation 注意:自定义注解必须配上注解的信息处理流程才有意义 */ /** * @description: IP白名单注解 * @author: laizhenghua * @date: 2022/5/15 11:08 */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface IPWhiteList { /** * 详细白名单ip列表配置 */ String[] whiteIpList(); /** * *号匹配配置 例如 127.0.0.* */ String regex() default "127.0.0.*"; /** * ip范围配置 例如 127.0.0.[1-10] */ String range(); }2、拦截器开发2.1、功能点描述

自定好注解后,我们就要来完成拦截器的编码工作。想要实现的效果为在某个controller层的请求方法上添加我们自定义的注解,自定义的注解配置可访问的IP地址白名单。然后我们通过拦截器,获取客户端的真实IP地址与注解配置信息。进行相关校验(校验规则也是自定义),如果校验通过则允许访问或执行请求方法否则不予访问。

例如:当检测到客户端IP地址与注解配置的IP地址没有在规则允许范围内,就返回如下信息。

Java如何配置白名单 java白名单如何实现_Java如何配置白名单_02

2.2、ip白名单拦截器编写/** * @description: IP白名单拦截器 * @author: laizhenghua * @date: 2022/5/15 11:43 */ public class IPWhiteListInterceptor implements HandlerInterceptor { private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(IPWhiteListInterceptor.class); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 1.获取自定义注解 HandlerMethod handlerMethod = (HandlerMethod) handler; IPWhiteList ipWhiteList = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), IPWhiteList.class); if (ipWhiteList == null) { return true; } // 2.获取客户端真实ip地址 String clientIp = getClientIpAddr(request); // 3.校验ip地址 String[] whiteIpList = ipWhiteList.whiteIpList(); for (String ip : whiteIpList) { if (ip.equals(clientIp)) { return true; } } fallback(clientIp, response); return false; } private void fallback(String clientIp, HttpServletResponse response) { response.setCharacterEncoding("UTF-8"); response.setContentType(MediaType.APPLICATION_JSON_VALUE); PrintWriter writer = null; try { String message = String.format("您的IP地址为[%s],已被系统禁止访问,请联系管理员处理!", clientIp); R error = R.error(403, message); JSONObject json = new JSONObject(error); writer = response.getWriter(); writer.append(json.toString()); } catch (IOException e) { log.error(e); } finally { if (writer != null) { writer.close(); } } } private String getClientIpAddr(HttpServletRequest request) { String ip = request.getHeader("X-Forwarded-For"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 if (ip != null && ip.length() > 15) { // "***.***.***.***".length() = 15 if (ip.indexOf(",") > 0) { ip = ip.substring(0, ip.indexOf(",")); } } return ip; } }2.3、注册拦截器并指定拦截路径规则

拦截器注册到容器中(实现 WebMvcConfigurer 的 addInterceptors() 方法),并制定拦截规则。如:

/** * @description: * @author: laizhenghua * @date: 2022/5/15 13:54 */ @Configuration public class IPWhiteListWebMvcConfiguration implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { // registry 拦截器注册中心 registry.addInterceptor(new IPWhiteListInterceptor()) .addPathPatterns("/user/**"); // 只拦截 /user 下的所有请求 } }2.4、编写测试方法进行测试

注意看注解@IPWhiteList的使用。

/** * @description: * @author: laizhenghua * @date: 2022/5/4 17:54 */ @RestController @RequestMapping(value = "/user") public class UserController { @Autowired private UserService userService; @IPWhiteList(whiteIpList = {"127.0.0.2"}, range = "") @RequestMapping(value = "/getList", method = RequestMethod.GET) public R getList() { return R.ok().put("data", userService.getList()); } }

我们本地的客户端IP地址是127.0.0.1,而接口http://127.0.0.1:8080/user/getList配置的允许访问的IP地址为127.0.0.2。我们自定义的校验规则也只是判断是否相等,因此本地访问是校验不通过的。

Java如何配置白名单 java白名单如何实现_拦截器_03

3、总结

到这里自定义注解配合拦截器完成业务方法的功能增强已经结束,其实也很简单就是简单的处理注解信息。重要的是要学会这种开发模式,去满足特定的应用场景!例如应用系统的日志、安全、缓存、事务等一些场景。这里也只是用一个简单的小例子介绍注解在实际开发中的应用方式。当然IP地址白名单的配置规则我们也只考虑了相等的情况,后面还可以配置范围和*正则匹配,可自行下去思考。

ENDTHANK YOU



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3