vlambda博客
学习文章列表

技术无边界 | Nginx+lua+Redis实现禁止黑名单访问


我们之前有写过Nginx系列文章,知道lua是可以很好地和Nginx配合使用的,可以在进入代码之前做一些处理,我们今天不妨尝试结合Redis来实现禁止黑名单访问的demo。

这里我们力求简单,省去安装,使用OpenResty,安装我们之前曾操作过,请看这一篇文章。


我是在windows7电脑上测试使用,主要配置代码如下:

 
   
   
 
  1. # 分配内存,根据业务量

  2. lua_shared_dict ip_blacklist 1m;


  3. server {

  4. listen 80;

  5. server_name localhost;


  6. root E:/www/web/test;


  7. access_log logs/host.access.log ;

  8. error_log logs/host.error.log;


  9. location / {

  10. access_by_lua_file ../lua/black.lua;

  11. index index.html index.htm;

  12. }



  13. error_page 500 502 503 504 /50x.html;

  14. location = /50x.html {

  15. root html;

  16. }



  17. location ~ \.php$ {

  18. # 指定lua文件

  19. access_by_lua_file "D:\openresty-1.15.8.1-win64/lua/black.lua";

  20. fastcgi_pass 127.0.0.1:9000;

  21. fastcgi_index index.php;

  22. fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

  23. include fastcgi_params;

  24. }

  25. }

black.lua

 
   
   
 
  1. local redis_port = "6379"


  2. -- 连接超时时间,单位ms,不建议设置太高

  3. local redis_connection_timeout = 1000


  4. local redis_key = "ip_blacklist"


  5. -- 缓存时间,单位s

  6. local cache_ttl = 100


  7. -- 以上是配置


  8. local ip = ngx.var.remote_addr

  9. local ip_blacklist = ngx.shared.ip_blacklist

  10. local last_update_time = ip_blacklist:get("last_update_time");


  11. -- 当缓存时间到期更新blacklist

  12. if last_update_time == nil or last_update_time < ( ngx.now() - cache_ttl ) then


  13. local redis = require "resty.redis";

  14. local red = redis:new();


  15. red:set_timeout(redis_connect_timeout);


  16. local ok, err = red:connect(redis_host, redis_port);


  17. if not ok then

  18. ngx.say("redis connect failed: ", err)

  19. ngx.log(ngx.DEBUG, "Redis connection error while retrieving ip_blacklist: " .. err);

  20. return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)

  21. else

  22. -- local res, err = red:auth("foobared") -- 配置redis的密码,我测试未设置密码,代码注释


  23. --if not res then

  24. --ngx.say("redis auth is error: ", err)

  25. --return

  26. --end

  27. red:select(0) -- 设置redisdb

  28. local new_ip_blacklist, err = red:smembers(redis_key);

  29. if err then

  30. ngx.log(ngx.DEBUG, "Redis read error while retrieving ip_blacklist: " .. err);

  31. else

  32. -- 情况本地存储

  33. ip_blacklist:flush_all();

  34. for index, banned_ip in ipairs(new_ip_blacklist) do

  35. ip_blacklist:set(banned_ip, true);

  36. end


  37. -- 更新时间

  38. ip_blacklist:set("last_update_time", ngx.now());

  39. end

  40. end

  41. end



  42. if ip_blacklist:get(ip) then

  43. --ngx.say(ip)

  44. ngx.log(ngx.DEBUG, "Banned IP detected and refused access: " .. ip);

  45. return ngx.exit(ngx.HTTP_FORBIDDEN);

  46. end

完成。

当然了,这只是个基础版本,你可以让这个禁止访问功能更强大,比如增加可疑ip写入,比如增加ip限流等等。