广告位联系
返回顶部
分享到

Springboot限制IP访问指定的网址实现

java 来源:互联网 作者:佚名 发布时间:2024-05-09 22:08:29 人浏览
摘要

IP黑白名单是网络安全管理中常见的策略工具,用于控制网络访问权限,根据业务场景的不同,其应用范围广泛 方式一: 添加一个简单的白名单,然后只有白名单上面的 IP 才能访问网站,否则

IP黑白名单是网络安全管理中常见的策略工具,用于控制网络访问权限,根据业务场景的不同,其应用范围广泛

方式一:

添加一个简单的白名单,然后只有白名单上面的 IP 才能访问网站,否则不能访问这是只是一个很简单的实现方法
首先:在 application.yml 配置 IP 白名单

1

2

3

4

5

6

my:

  ipList:

    - 192.168.3.3

    - 192.168.2.12

    - 192.168.5.24

    - 152.63.54.26

想要引用到配置文件里面的 String 数组,如果使用普通的 @Value 是不行的,必须使用其他方法

步骤一:创建一个实体类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

@Component

@ConfigurationProperties(prefix = "my") // 这里是对应的配置文件里面自定义的 my

public class My {

 

    private String[] ipList;

 

    public My(String[] ipList) {

        this.ipList = ipList;

    }

 

    public String[] getIpList() {

        return ipList;

    }

 

    public void setIpList(String[] ipList) {

        this.ipList = ipList;

    }

}

这样配置文件的信息就保存在了这个实体类里面
在 Controller 里面比对 IP

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

@Controller

public class LoginController {

 

    @Autowired

    private My myIpList;

 

    @PostMapping("/login")

    @ResponseBody

    public String login(@RequestBody LoginForm loginForm, HttpServletRequest request) {

        String [] ipList = myIpList.getIpList();

 

        String IPAddress = loginForm.getIpAddress();

        // 如果前端传递过来的 IP 在白名单里面,就返回 OK,如果不在,就返回 error

        for (String s : ipList) {

            if (s.equals(IPAddress)) {

                return "OK";

            }

        }

        return "error";

    }

 

}

方式二:限制 IP 访问的次数

这个是利用了 aop 的切面编程,如果同一个 IP 访问一个地址一分钟之内超过10次,就会把这个 IP 拉入黑名单,在自定义的时间内是不能再次访问这个网站的。

第一步,在 application.yml 中配置 Redis 相关设置

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

spring:

  redis:

    # 超时时间

    timeout: 10000ms

    # 服务器地址

    host: 192.168.1.1

    # 服务器端口

    port: 6379

    # 数据库

    database: 0

    # 密码

    password: xxxxxxx

    lettuce:

      pool:

        # 最大连接数,默认为 8

        max-active: 1024

        # 最大连接阻塞等待时间,默认 -1

        max-wait: 10000ms

        # 最大空闲连接

        max-idle: 200

        # 最小空闲连接

        min-idle: 5

第一步,自定义一个注解

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

@Documented

@Order(Ordered.HIGHEST_PRECEDENCE)

public @interface RequestLimit {

 

    /**

     * 允许访问的最大次数

     */

    int count() default Integer.MAX_VALUE;

 

    /**

     * 时间段,单位为毫秒,默认值一分钟

     */

    long time() default 60000;

}

第二步:序列化 redis 类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

@Configuration

@Slf4j

public class RedisConfiguration {

 

    @Bean

    @ConditionalOnMissingBean

    public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) {

        System.err.println("调用了 Redis 配置类");

        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();

        // String 类型 key 序列器

        redisTemplate.setKeySerializer(new StringRedisSerializer());

        // String 类型 value 序列器

        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());

        // Hash 类型 value 序列器

        redisTemplate.setHashKeySerializer(new StringRedisSerializer());

        // Hash 类型 value 序列器

        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());

        redisTemplate.setConnectionFactory(connectionFactory);

        return redisTemplate;

    }

}

第三步:创建一个切面类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

@Aspect

@Component

@Slf4j

public class RequestLimitContract {

 

 

    private static final Logger logger = LoggerFactory.getLogger("requestLimitLogger");

 

    @Autowired

    private RedisTemplate<String, Object> redisTemplate;

    @Autowired

    private ObjectMapper objectMapper;

 

    @Before("within(@org.springframework.stereotype.Controller *) && @annotation(limit)")

    public void requestLimit(final JoinPoint joinPoint , RequestLimit limit) throws RequestLimitException {

        try {

            LoginForm loginForm = new LoginForm();

            Object[] args = joinPoint.getArgs();

            HttpServletRequest request = null;

            for (int i = 0; i < args.length; i++) {

                if (args[i] instanceof HttpServletRequest) {

                    request = (HttpServletRequest) args[i];

                    break;

                } else if (args[i] instanceof LoginForm) {

                    loginForm = (LoginForm) args[i];

                }

 

            }

            if (request == null) {

                throw new RequestLimitException("方法中缺失HttpServletRequest参数");

            }

 

            //获取请求中的ip与url链接参数 用于拼接key存放redis中

            String ip = loginForm.getIpAddress();

            String url = request.getRequestURL().toString();

            Long  interview_time = new Date().getTime();

            String key = "req_limit_".concat(url).concat("---").concat(ip);

            System.err.println("准备保存在redis中的数据为-->");

            Map<String, Long> form = new HashMap<>();

            form.put("size", 1L);

            form.put("saveRedisTime", interview_time);

 

            if (redisTemplate.opsForValue().get(key) == null) {

                System.err.println(form);

                redisTemplate.opsForValue().set(key, form);

            } else {

                //用于进行ip访问的计数

                Map<String, Long> result = (Map<String, Long>) redisTemplate.opsForValue().get(key);

                System.err.println("从redis取到的数据(内部)");

                System.out.println(result);

 

                assert result != null;

                result.put("size", result.get("size") + 1);

                redisTemplate.opsForValue().set(key, result);

 

 

                if (result.get("size") > 10) {

                    logger.info("用户IP[" + ip + "]访问地址[" + url + "]超过了限定的次数[" + limit.count() + "]");

                    throw new RequestLimitException();

                }

 

                // 如果访问次数小于 10 次,那么一分钟过后就直接删除这个节点

                if (result.get("size") <= limit.count()) {

                    //创建一个定时器

                    Timer timer = new Timer();

                    TimerTask timerTask = new TimerTask() {

                        @Override

                        public void run() {

                            redisTemplate.delete(key);

                        }

                    };

                    //这个定时器设定在time规定的时间之后会执行上面的remove方法,也就是说在这个时间后它可以重新访问

                    timer.schedule(timerTask, limit.time());

                }

            }

        }catch (RequestLimitException e){

            throw e;

        }catch (Exception e){

            logger.error("发生异常",e);

        }

    }

}

第四步,创建一个定时器

记住要在启动类上面开启启动定时器注解

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

@Component

public class ScheduledTask {

 

    @Autowired

    private RedisTemplate<String, Object> redisTemplate;

 

//    @Value("${properties.continueTime}")

    private final long continueTime = 120;  // 这是是黑名单的保存时间,在这个时间内,同一个IP将不能继续访问

    //    @Scheduled(cron = "0 0 0 * * ?") // 每天凌晨触发一次

    @Scheduled(fixedRate = 1000000) // 每 30s 执行一次

    public void deleteDataScheduled() {

        Set<String> keys = redisTemplate.keys("*");

        if (keys == null || keys.size() == 0) {

            return;

        }

        System.out.println("redis里面所有的key为:" + keys.toString());

 

        long now_time = new Date().getTime();

 

        for (String key : keys) {

            Map<String, Long> result = (Map<String, Long>) redisTemplate.opsForValue().get(key);

            assert result != null;

            System.err.println(result);

            // 计算出时间差

            long createTime = result.get("saveRedisTime");

            System.err.println("创建时间为:" + createTime);

            long l = (now_time - createTime) / 1000L;

            System.err.println("时间差为:" + l);

            if (l > continueTime) {

                System.out.println("禁止时间结束,解除时间限制!!!");

                redisTemplate.delete(key);

                return;

            }

            int s = Math.toIntExact(result.get("size"));

            System.out.println("s===>" + s + "   l===>" + l);

            if (s <= 10) {

                if (l > 60) {

                    System.out.println("一分钟结束,删除节点,重新计时");

                    redisTemplate.delete(key);

                }

            }

        }

    }

}

第五步:在需要的类上使用自己自定义的注解

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

@PostMapping("/login")

    @RequestLimit(count=10,time=60000)   // 这个注解就是开启IP限制的注解,这个注解的业务都是自己写的

    @ResponseBody

    public String login(@RequestBody LoginForm loginForm, HttpServletRequest request) {

 

        System.out.println("执行登录代码");

 

        String name = loginForm.getUsername();

        String IPAddress = loginForm.getIpAddress();

        String timestamp = String.valueOf(new Date().getTime());

        String info = Arrays.toString(ipList);

 

        request.setAttribute("userName", name);

        request.setAttribute("ipAddress", IPAddress);

 

        return "OK1";

    }

总结:在这里针对 IP 的限制就结束了,总而言之还是比较简单的,没有什么特别难的点


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 :
相关文章
  • idea没有services窗口、没有springboot启动项问题

    idea没有services窗口、没有springboot启动项问题
    idea没有services窗口、没有springboot启动项 idea没有services窗口 没有springboot启动项。 如果是找不到services窗口,可以在views的tools Windows下找到
  • Springboot限制IP访问指定的网址实现

    Springboot限制IP访问指定的网址实现
    IP黑白名单是网络安全管理中常见的策略工具,用于控制网络访问权限,根据业务场景的不同,其应用范围广泛 方式一: 添加一个简单的白
  • MybatisPlus多条件or()的使用问题小结

    MybatisPlus多条件or()的使用问题小结
    搞混了一次,特此笔记 1、bitCode or iotStr 跟其他ID一个都不能有重复 1 2 queryWrapper.ne(LineProductionPlan::getId,bean.getId()); queryWrapper.and(i - i.eq(LineP
  • 升级springboot3.x踩坑记录
    0x01 redis连接异常 先贴一张项目启动的堆栈信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 4
  • springBoot连接远程Redis连接失败的问题解决
    问题: 首先,我是先用jedis进行的redis连接,成功连接,没有任何问题,说明redis配置,以及访问地址、端口、密码都是正确的。 我的yml文件
  • Java Stream API详解与使用介绍

    Java Stream API详解与使用介绍
    本文全面介绍了 Java Stream API 的概念、功能以及如何在 Java 中有效地使用它进行集合和数据流的处理。通过详细解释和示例,文章展示了 J
  • Springboot如何使用外部yml启动

    Springboot如何使用外部yml启动
    Springboot使用外部yml启动 有时候我们想更灵活的使用配置文件,例如同一套代码去部署多个客户,此时差异大的地方其实只是配置文件,这是
  • java如何获取视频文件的编解码器代码
    引入jar包: 1 2 3 4 5 dependency groupIdorg.bytedeco/groupId artifactIdjavacv-platform/artifactId version1.5.9/version /dependency 测试类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
  • Java服务cpu100%的解决过程分享

    Java服务cpu100%的解决过程分享
    背景 最近一个任务是优化一个导出的功能,但是点击功能时发现,程序长时间无反应,过一段时间又有反应,通过查看服务的监控发现,服
  • Spring中实现策略模式的几种方式小结
    一.背景 在写业务代码的时候,难免会遇到很多if-else,这个时候如果if-else不是很多可以用if-else。如果此时场景过多,太多的if-else会导致代
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计