Nginx鉴权、限流问题

 更新时间:2024年06月19日 10:49:48   作者:yancqitcode  

这篇文章主要介绍了Nginx鉴权、限流问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

目录
  • 一、Nginx鉴权
    • 1. 依赖模块 依赖模块
    • 2. Nginx配置
    • 3. Rest接口
  • 二、Nginx限流
    • 1. 简介
    • 2. 控制速率
    • 3. 控制连接数
  • 总结

    一、Nginx鉴权

    1. 依赖模块 依赖模块

    • 依赖模块
    http_auth_request_module
    • 验证是否安装
    nginx -V 2>&1 | grep -- 'http_auth_request_module'
    

    2. Nginx配置

    server
    {
    	listen 80;
    
    	location = /checkToken {
    		internal;
    		proxy_pass_request_body off;
    		proxy_set_header Content-Length "";
    		proxy_set_header via $request_uri;
    		proxy_pass $auth_request_url;
    	}
    
    	location = /auth401 {
    		add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate";
    		if ( $arg_via = "001" ) {
    			return 401 "{\"msg\":\"登录凭证为空\",\"opCode\":\"001\",\"operateSuccess\":false}";
            }
    		if ( $arg_via = "002" ) {
    			return 401 "{\"msg\":\"登录凭证失效\",\"opCode\":\"002\",\"operateSuccess\":false}";
            }
            if ( $arg_via = "003" ) {
    			return 401 "{\"msg\":\"账户无权限\",\"opCode\":\"003\",\"operateSuccess\":false}";
            }
    	}
    
    	location /test/api/ {
    		set $auth_request_url "http://127.0.0.1:8080/test/api/token/check?token=$arg_token";
    		auth_request /checkToken;
    		auth_request_set $auth_via $upstream_http_via;
    		error_page 401 = /auth401?via=$auth_via;
    		
    		proxy_pass http://127.0.0.1:8080/test/api/;
    	}
    
    }
    

    3. Rest接口

    • 验证的Redis账户权限内容
    • TokenRest.java
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import javax.annotation.Resource;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.Map;
    import java.util.Set;
    
    @RestController
    @RequestMapping("/api/token")
    public class TokenRest {
    
    	@Resource
    	private RedisTemplate redisTemplate;
    
    	@GetMapping(value="check")
    	public void checkRest(HttpServletRequest request, HttpServletResponse response) {
    		response.setStatus(401);
    		try {
    			String url = request.getHeader("via");
    			if (StringUtils.isNotEmpty(url) && url.contains("?")) {
    				url = url.substring(0, url.indexOf("?"));
    			}
    			// 白名单跳过验证
    			String flag = (String) redisTemplate.opsForHash().get("whiteCache", url);
    			if (StringUtils.isNotEmpty(flag)) {
    				response.setStatus(200);
    				return;
    			}
    			// 从Head或url中获取token
    			String token = request.getParameter("token");
    			if (StringUtils.isEmpty(token) || "null".equals(token)) {
    				token = request.getHeader("Authorization");
    				if (token!=null && token.startsWith("Bearer ")) {
    					token = token.substring(7);
    				}
    			}
    			if (StringUtils.isEmpty(token) || "null".equals(token)) {
    				response.setHeader("via", "001");
    				return;
    			}
    			// 从Redis中获取账户信息
    			String accountId = (String) redisTemplate.opsForValue().get(token);
    			if (accountId == null) {
    				response.setHeader("via", "002");
    				return;
    			}
    			Map<String, String> info = (Map<String, String>) redisTemplate.opsForValue().get(accountId);
    			if (info == null) {
    				response.setHeader("via", "003");
    				return;
    			}
    			String[] roleIds = info.get("roles").split(",");
    			for (String roleId : roleIds) {
    				Set<String> securityUrls = (Set<String>) redisTemplate.opsForHash().get("funcCache",roleId);
    				if (securityUrls.contains(url)) {
    					flag = "1";
    					break;
    				}
    			}
    			if ("1".equals(flag)) {
    				response.setStatus(200);
    			} else {
    				response.setHeader("via", "003");
    			}
    		} catch (Exception e) {
    			System.err.println(e.getMessage());
    		}
    	}
    }
    
    • 验证的Redis账户权限内容

    在这里插入图片描述

    二、Nginx限流

    1. 简介

    Nginx限流是一种用于保护系统资源、防止恶意攻击和控制流量的技术。

    • 控制速率:使用 ngx_http_limit_req_module 模块,可以限制每个IP地址单位时间内的请求数。
    • 控制连接数:使用 ngx_http_limit_conn_module 模块,可以限制每个IP地址同时保持的连接数。

    2. 控制速率

    • nginx.conf
    http
    {
    	limit_req_zone $binary_remote_addr zone=limit_req:10m rate=2r/s;
    }
    
    说明
    binary_remote_addr 表示通过客户端IP来限制
    zone 共享内存区存储访问信息
    limit_req:10m 名字为limit_req的内存区域,存储16万IP地址
    rate=2r/s 表示每秒最多处理2个请求
    server
    {
    	location = /test.htm {
    		limit_req zone=limit_req burst=10 nodelay;
    		alias C:/nginx/html/test.htm;
    	}
    }
    
    说明
    burst=10 突发请求不超过10个
    nodelay 不延迟处理超过限制的请求

    3. 控制连接数

    • nginx.conf
    http
    {
    	limit_conn_zone $binary_remote_addr zone=limit_conn:10m;
    }
    
    说明
    binary_remote_addr 表示通过客户端IP来限制
    zone 共享内存区存储访问信息
    limit_conn:10m 名字为limit_conn的内存区域,存储16万IP地址
    server
    {
    	location = /test.htm {
    		limit_conn limit_conn 2;
    		alias C:/nginx/html/test.htm;
    	}
    }
    
    说明
    limit_conn 2 同一个IP地址只允许保持2个连接

    总结

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持小闻网。

    声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。