一、Nginx鉴权
1. 依赖模块 依赖模块
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 info = (Map) redisTemplate.opsForValue().get(accountId);
if (info == null) {
response.setHeader("via", "003");
return;
}
String[] roleIds = info.get("roles").split(",");
for (String roleId : roleIds) {
Set securityUrls = (Set) 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());
}
}
}
二、Nginx限流
1. 简介
Nginx限流是一种用于保护系统资源、防止恶意攻击和控制流量的技术。
- 控制速率:使用
ngx_http_limit_req_module
模块,可以限制每个IP地址单位时间内的请求数。
- 控制连接数:使用
ngx_http_limit_conn_module
模块,可以限制每个IP地址同时保持的连接数。
2. 控制速率
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. 控制连接数
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个连接 |
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持IT俱乐部。