群控系统服务端开发模式-应用开发-业务架构逻辑开发第一轮测试

整个系统的第一个层次已经开发完毕,已经有简单的中控,登录、退出、延迟登录时长、黑名单、数据层封装、验证层封装、RSA加解密、Redis等功能,还缺获取个人、角色按钮权限、角色菜单权限功能。角色按钮权限以及角色菜单权限等明后天开发,今天先开发个人信息接口以便测试使用。

一、个人信息接口开发

1、添加路由

在根目录下route文件夹中的app.php文件中加入以下代码:

Route::post('member/personal_data','permission.Member/personalData');

2、代码开发

在根目录下app文件夹下的controller文件夹中创建文件夹并命名为permission,然后在permission文件夹中创建控制器并命名为Member,然后在Member文件中继承Base总控制后并创建personalData方法。具体代码如下:

<?php
/**
 * 个人信息控制-也就是登录者信息及角色对外方法
 * User: 龙哥·三年风水
 * Date: 2024/10/30
 * Time: 14:18
 */
namespace app\controller\permission;
use app\controller\Base;
class Member extends Base
{
    /**
     * 获取个人信息
     * User: 龙哥·三年风水
     * Date: 2024/10/30
     * Time: 14:23
     * @ return \think\response\Json
     */

    public function personalData(){
        $data = [];
        $data['username'] = $this->username;
        $data['avatar'] = $this->avatar;
        $data['email'] = $this->email;
        $data['realname'] = $this->realname;
        return succ('操作成功',$data);
    }
}

二、nginx黑名单开发

因nginx自身是没有redis及rsa扩展使用的,所以我安装的不是nginx,而是openresty,他是有带resty扩展的。如果不会安装openresty,可以参照《centos7 二进制安装openresty》、《配置openresty》以及《openresty安全机制-白名单》三篇文章进行安装配置。

1、引入扩展

--引入Redis
local redis = require "resty.redis";
--引入rsa
local rsa = require "resty.rsa";

2、配置redis

--Redis链接ip
local ip = "172.20.36.144"
--Redis链接端口
local port = 6379
--Redis连接密码
local pass = "QXtr@@PxjoLenGon"

3、在对应的Redis库里面添加公钥字符串

我不管是在应用程序里面还是在本机制里面,都采用的是Redis第0号库的black-list库中哈,所有的非正常访问系统的IP都在black-list库中。

4、开发lua对应的Redis授权

--鉴权Redis
local function connAuth()
	local red = redis:new();
	local connCount, err = red:connect(ip, port);
	if not connCount then
		ngx.say("failed to connect: ", err)
		close_redis(red)
		return
	end
	red:set_timeouts(2000);
	local ok, err = red:auth(pass)
	if not ok then
		ngx.say("failed to auth: ", err)
		close_redis(red)
		return
	end
	return red
end

5、开发lua对应的Redis关闭

--关闭Redis
local function close_redis(red)
    if not red then
        return
    end
    --释放连接(连接池实现)
    local pool_max_idle_time = 10000
    local pool_size = 100
    local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)
    if not ok then
        ngx.say("set keepalive error : ", err)
    end
end

6、开发获取请求者IP

--获取请求者IP
local function getIp()
    local clientIP = ngx.req.get_headers()["X-Real-IP"]
    if clientIP == nil then
        clientIP = ngx.req.get_headers()["x_forwarded_for"]
    end
    if clientIP == nil then
        clientIP = ngx.var.remote_addr
    end
    return clientIP
end
--获取用户访问IP
local clientIP = getIp();
--封禁token时间(秒)
local token_block_time= 120
--指定token访问频率计数最大值(次)
local token_max_count = 3

7、开发空方法

--如果数据为空的情况下
local function is_empty(value)
    if type(value) == "table" then
        return next(value) == nil
    elseif type(value) == "string" then
        return #value == 0
    elseif type(value) == "nil" then
        return true
    end
        return false
end

8、过滤特殊字符串

--过滤特殊字符串(只保留字母与数字,字母不区分大小写)
local function filter_special_chars(s)
    local ss = {}
    local k = 1
    while true do
        if k > #s then break end
        local c = string.byte(s,k)
        if not c then break end
        if c<192 then
            if (c>=48 and c<=57) or (c>= 65 and c<=90) or (c>=97 and c<=122) then
                table.insert(ss, string.char(c))
            end
            k = k + 1
        end
    end
    return table.concat(ss)
end

9、组合开发黑名单机制

--引入Redis
local redis = require "resty.redis";
--引入rsa
local rsa = require "resty.rsa";
--Redis链接ip
local ip = "172.20.36.144"
--Redis链接端口
local port = 6379
--Redis连接密码
local pass = "QXtr@@PxjoLenGon"
--鉴权Redis
local function connAuth()
	local red = redis:new();
	local connCount, err = red:connect(ip, port);
	if not connCount then
		ngx.say("failed to connect: ", err)
		close_redis(red)
		return
	end
	red:set_timeouts(2000);
	local ok, err = red:auth(pass)
	if not ok then
		ngx.say("failed to auth: ", err)
		close_redis(red)
		return
	end
	return red
end

--关闭Redis
local function close_redis(red)
    if not red then
        return
    end
    --释放连接(连接池实现)
    local pool_max_idle_time = 10000
    local pool_size = 100
    local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)
    if not ok then
        ngx.say("set keepalive error : ", err)
    end
end

--获取请求者IP
local function getIp()
    local clientIP = ngx.req.get_headers()["X-Real-IP"]
    if clientIP == nil then
        clientIP = ngx.req.get_headers()["x_forwarded_for"]
    end
    if clientIP == nil then
        clientIP = ngx.var.remote_addr
    end
    return clientIP
end
--获取用户访问IP
local clientIP = getIp();
--封禁token时间(秒)
local token_block_time= 120
--指定token访问频率计数最大值(次)
local token_max_count = 3

--如果数据为空的情况下
local function is_empty(value)
    if type(value) == "table" then
        return next(value) == nil
    elseif type(value) == "string" then
        return #value == 0
    elseif type(value) == "nil" then
        return true
    end
        return false
end

--过滤特殊字符串(只保留字母与数字,字母不区分大小写)
local function filter_special_chars(s)
    local ss = {}
    local k = 1
    while true do
        if k > #s then break end
        local c = string.byte(s,k)
        if not c then break end
        if c<192 then
            if (c>=48 and c<=57) or (c>= 65 and c<=90) or (c>=97 and c<=122) then
                table.insert(ss, string.char(c))
            end
            k = k + 1
        end
    end
    return table.concat(ss)
end

--如果头部信息没有指定的参数或是指定参数的值无法解析,加入IP黑名单
--如果同样的头部参数键在封禁token时间内连续访问指定token访问频率计数最大值次以上,加入IP黑名单----暂时还没有开发,开发测试好后,将重新更新
local function set_blacklist()
    local header = ngx.req.get_headers();
    local red = connAuth();
	local token, err = header["Authorization"];
    -- 如果参数为空的情况下
	if not token then
        local res, err =  red:sismember('black-list', clientIP);
        if res ~= 1 then
            red:sadd('black-list', clientIP)
        end
        close_redis(red)
        return ngx.exit(401)
    else
        -- 如果参数值为空的情况下
        if is_empty(token) then
            local res, err =  red:sismember('black-list', clientIP);
            if res ~= 1 then
                red:sadd('black-list', clientIP)
            end
            close_redis(red)
            return ngx.exit(401)
        end
        -- 如果参数值采用base64解析不开的情况下
        local encrypted, err = tostring(ngx.decode_base64(token))
        if not encrypted then
            local res, err =  red:sismember('black-list', clientIP);
            if res ~= 1 then
                red:sadd('black-list', clientIP)
            end
            close_redis(red)
            return ngx.exit(401)
        end
        -- 采用rsa技术解析token base64过后的值内容
        local priv_key = '-----BEGIN PRIVATE KEY-----\n' ..red:get('priv_key_cluster_control')..'\n-----END PRIVATE KEY-----';
        local priv, err = rsa:new({private_key = priv_key})
        local dst, err = rsa.decrypt(priv, encrypted)
        if not dst then
            local res, err =  red:sismember('black-list', clientIP);
            if res ~= 1 then
                red:sadd('black-list', clientIP)
            end
            close_redis(red)
            return ngx.exit(401)
        end
    end
end

-- 查看是否在黑名单里面
local function get_blacklist()
    local red = connAuth();
    local res, err =  red:sismember('black-list', clientIP);
    if res == 1 then
        close_redis(red);
        return ngx.exit(401);
    end
    close_redis(red);
end

get_blacklist();
set_blacklist();

10、将开发好的lua文件也一并上传到网站目录中,然后更改nginx应用配置文件,然后重新启动nginx,代码如下:

server {
        listen        80;
        server_name controlapi.yuanlongsoftware.cn;
        error_log /data/nginx/controlapi.yuanlongsoftware.cn80_error.log crit;
        access_log /data/nginx/controlapi.yuanlongsoftware.cn80_acess_$logdate.log access-upstream;
        lua_code_cache off;
        autoindex off;
        server_tokens off;
        error_page   401 /401.html;
        location / {
                if ($request_method ~* OPTIONS) {
                        return 200;
                }
                access_by_lua_file /data/wwwroot/teach/group_control/cluster_control/rsa-cluster-control.lua;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                add_header 'Access-Control-Allow-Credentials' 'true';
                add_header Access-Control-Allow-Origin "$http_origin";
                add_header Access-Control-Allow-Headers 'X-Requested-With,Cache-Control,Content-Type,Authorization';
                add_header Cache-Control no-cache;
                add_header 'Access-Control-Allow-Methods' 'GET, POST';
                proxy_pass http://controlapi;
        }
        location = /401.html {
            root "/data/wwwroot/error";
        }
}

三、测试

1、登录后用token去获取一下用户信息接口,采用apipost工具测试

2、采用同一个token再次去获取一下用户信息接口,采用apipost工具再次测试

3、采用同一个token再次去获取一下用户信息接口,采用apipost工具再次测试

第二次以后,就是openresty直接返回咯,因lua去检测是发现他就在黑名单中,就直接返回。

其实后期我还会出对应的精简文章,也就是优化过后的文章。

四、提前说明

明后天将带来管理员功能开发、角色功能开发、菜单功能开发以及上传文件开发

相关推荐
007php0072 小时前
Go语言zero项目部署后启动失败问题分析与解决
java·服务器·网络·python·golang·php·ai编程
zquwei3 小时前
SpringCloudGateway+Nacos注册与转发Netty+WebSocket
java·网络·分布式·后端·websocket·网络协议·spring
卜及中6 小时前
【Linux】资源隔离机制 — 命名空间(Namespace)详解
linux·服务器·php
m0_548514777 小时前
2024.12.10——攻防世界Web_php_include
android·前端·php
道一云黑板报7 小时前
Flink集群批作业实践:七析BI批作业执行
大数据·分布式·数据分析·flink·kubernetes
网络安全King8 小时前
网络安全 - SQL Injection
sql·web安全·php
图图爱上壮壮妈8 小时前
PHP中实现拓扑算法
开发语言·算法·php
飞来又飞去9 小时前
kafka sasl和acl之间的关系
分布式·kafka
MZWeiei10 小时前
Zookeeper的监听机制
分布式·zookeeper
莹雨潇潇10 小时前
Hadoop完全分布式环境部署
大数据·hadoop·分布式