Openresty最佳案例 | 第8篇:RBAC介绍、sql和redis模块工具类
转载请标明出处:
http://blog.csdn.net/forezp/article/details/78616738
本文出自方志朋的博客
RBAC介绍
RBAC(Role-Based Access Control,基于角色的访问控制),用户基于角色的访问权限控制。简单地说,一个用户拥有若干角色,每一个角色拥有若干权限。这样,就构造成“用户-角色-权限”的授权模型。在这种模型中,用户与角色之间,角色与权限之间,一般都是多对多的关系。如图所示:
sql_tool
在本案例中,采用的就是这种权限设计的方式。具体的sql语句脚本如下:
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT ,
`name` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=latin1 COLLATE=latin1_swedish_ci
AUTO_INCREMENT=2
ROW_FORMAT=COMPACT
;
CREATE TABLE role(
`id` int(11) NOT NULL AUTO_INCREMENT ,
`name` varchar(255) CHARACTER SET latin5 NULL DEFAULT NULL ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=latin1 COLLATE=latin1_swedish_ci
AUTO_INCREMENT=2
ROW_FORMAT=COMPACT
;
CREATE TABLE permission(
`id` int(11) NOT NULL AUTO_INCREMENT ,
`permission` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=latin1 COLLATE=latin1_swedish_ci
AUTO_INCREMENT=3
ROW_FORMAT=COMPACT
;
CREATE TABLE user_role(
`id` int(11) NOT NULL AUTO_INCREMENT ,
`user_id` int(11) NULL DEFAULT NULL ,
`role_id` int(11) NULL DEFAULT NULL ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=latin1 COLLATE=latin1_swedish_ci
AUTO_INCREMENT=2
ROW_FORMAT=COMPACT
;
CREATE TABLE role_permission(
`id` int(11) NOT NULL AUTO_INCREMENT ,
`role_id` int(11) NULL DEFAULT NULL ,
`permission_id` int(11) NULL DEFAULT NULL ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=latin1 COLLATE=latin1_swedish_ci
AUTO_INCREMENT=3
ROW_FORMAT=COMPACT
;
初始化以下的sql脚本,即给用户id为1的用户关联角色,角色并关联权限:
INSERT INTO `permission` VALUES ('1', '/user/orgs');
INSERT INTO `role` VALUES ('1', 'user');
INSERT INTO `role_permission` VALUES ('1', '1', '1');
INSERT INTO `user` VALUES ('1', 'forezp');
INSERT INTO `user_role` VALUES ('1', '1', '1');
在本案例中,需要根据user表中的Id获取该Id对应的权限。首先根据userId获取该用户对应的角色,再根据根据该角色获取相应的权限,往往一个用户具有多个角色,而角色又有多个权限。比如查询userId为1 的用户的权限的sql语句如下:
SELECT a.id,a.permission from permission a ,role_permission b,role c,user_role d,user e WHERE a.id=b.permission_id and c.id=b.role_id and d.role_id=c.id and d.user_id=e.id and e.id=1"
在Openresty中怎么连接数据库,怎么查询sql语句,在之前的文章已将讲述过了。根据用户id获取用户的权限的功能是一个使用率极高的功能,所以考虑将这个功能模块化。
vim /usr/example/lualib/sql_tool.lua ,编辑加入以下的代码:
local mysql = require("resty.mysql")
local function close_db(db)
if not db then
return
end
db:close()
end
local function select_user_permission(user_id)
local db, err = mysql:new()
if not db then
ngx.say("new mysql error : ", err)
return
end
db:set_timeout(1000)
local props = {
host = "127.0.0.1",
port = 3306,
database = "test",
user = "root",
password = "123"
}
local res, err, errno, sqlstate = db:connect(props)
if not res then
ngx.say("connect to mysql error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
close_db(db)
end
local select_sql = "SELECT a.id,a.permission from permission a ,role_permission b,role c,user_role d,user e WHERE a.id=b.permission_id and c.id=b.role_id and d.role_id=c.id and d.user_id=e.id and e.id="..user_id
res, err, errno, sqlstate = db:query(select_sql)
if not res then
ngx.say("select error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
return close_db(db)
end
local permissions={}
for i, row in ipairs(res) do
for name, value in pairs(row) do
if name == "permission" then
table.insert(permissions, 1, value)
end
end
end
return permissions
end
local _M = {
select_user_permission= select_user_permission
}
return _M
在上面的代码中,有一个select_user_permission(user_id)方法,该方法根据用户名获取该用户的权限。查出来存在一个table 类型的 local permissions={}中。
vim /usr/example/example.conf 加上以下的代码:
location ~ /sql_tool{
default_type 'text/html';
content_by_lua_file /usr/example/lua/test_sql_tool.lua;
}
在浏览器上访问http://116.196.177.123/sql_tool,浏览器显示如下的内容:
/user/orgs
tokentool
在之前的文章讲述了如何使用Openresty连接redis,并操作redis。 这小节将讲述如何使用openresty连接redis,并写几个方法,用于存储用户的token等,并将这些信息模块化,主要有以下几个方法:
- close_redis(red) 通过连接池的方式释放一个连接
- connect() 连接redis
- has_token(token) redis中存在token 与否
- get_user_id(token) 根据token获取用户id
- set_permissions(user_id,permissions) 根据userid设置权限
- get_permissions(user_id)根据userid获取权限
vim /usr/example/lualib/tokentool.lua 编辑一下内容:
module("tokentool", package.seeall)
local redis = require "resty.redis"
local str = require "resty.string"
local cjson = require("cjson")
local redis_host = "127.0.0.1"
local redis_port = 6379
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
local function connect()
local red = redis:new()
red:set_timeout(1000)
local ok, err = red:connect(redis_host, redis_port)
if not ok then
return false
end
--local res, err = red:auth("xiaoantimes")
--if not res then
-- ngx.say("failed to authenticate: ", err)
-- return false
--end
--ok, err = red:select(1)
--if not ok then
-- return false
--end
return red
end
function has_token(token)
local red = connect()
if red == false then
return false
end
local res, err = red:get(token)
if not res then
return false
end
close_redis(red)
return true
end
function set_permissions(user_id,permissions)
if (permissions==null) or( permissions==ngx.null) then
return false
end
local str = cjson.encode(permissions)
ngx.log(ngx.ERR,"set redis p:"..str)
local red=connect()
if red== false then
return false
end
local ok, err = red:set(user_id,str)
if not ok then
return false
end
return true
end
function get_permissions(user_id)
local red=connect()
if red== false then
return false
end
local res, err = red:get(user_id)
if (not res) or (res == ngx.null) then
return
end
ngx.log(ngx.ERR,"get redis p:"..res);
local permissions=cjson.decode(res)
return permissions
end
function get_user_id(token)
local red = connect()
local resp, err = red:get(token)
if not resp then
ngx.say("get msg error : ", err)
return close_redis(red)
end
close_redis(red)
return resp
end
vim /usr/example/lua/test_token_tool.lua,加上以下的内容:
local tokentool= require "tokentool"
local ret = tokentool.has_token("msg")
ngx.log(ngx.ERR,ret)
if ret == true then
ngx.say("ok")
else
ngx.say("oops,error")
end
在/usr/example/example.conf加上以下的内容:
location ~ /token_tool{
default_type 'text/html';
lua_code_cache on;
content_by_lua_file /usr/example/lua/test_token_tool.lua;
}
打开浏览器访问http://116.196.177.123/token_tool,浏览器显示:
ok
扫码关注公众号有惊喜
(转载本站文章请注明作者和出处 方志朋的博客)
Openresty最佳案例 | 第8篇:RBAC介绍、sql和redis模块工具类的更多相关文章
- Openresty最佳案例 | 第2篇:Lua入门
转载请标明出处: http://blog.csdn.net/forezp/article/details/78616622 本文出自方志朋的博客 什么是lua Lua 是一种轻量小巧的脚本语言,用标准 ...
- Openresty最佳案例 | 第4篇:OpenResty常见的api
转载请标明出处: http://blog.csdn.net/forezp/article/details/78616660 本文出自方志朋的博客 获取请求参数 vim /usr/example/exa ...
- Openresty最佳案例 | 第1篇:Nginx介绍
转载请标明出处: http://blog.csdn.net/forezp/article/details/78616591 本文出自方志朋的博客 Nginx 简介 Nginx是一个高性能的Web 服务 ...
- Openresty最佳案例 | 第9篇:Openresty实现的网关权限控制
转载请标明出处: http://blog.csdn.net/forezp/article/details/78616779 本文出自方志朋的博客 简介 采用openresty 开发出的api网关有很多 ...
- Openresty最佳案例 | 第7篇: 模块开发、OpenResty连接Redis
转载请标明出处: http://blog.csdn.net/forezp/article/details/78616714 本文出自方志朋的博客 Lua模块开发 在实际的开发过程中,不可能把所有的lu ...
- Openresty最佳案例 | 第6篇:OpenResty连接Mysql
转载请标明出处: http://blog.csdn.net/forezp/article/details/78616698 本文出自方志朋的博客 centos 安装mysl Centos系统下安装my ...
- Openresty最佳案例 | 第5篇:http和C_json模块
转载请标明出处: http://blog.csdn.net/forezp/article/details/78616672 本文出自方志朋的博客 http客户端 Openresty没有提供默认的Htt ...
- Openresty最佳案例 | 第3篇:Openresty的安装
转载请标明出处: http://blog.csdn.net/forezp/article/details/78616645 本文出自方志朋的博客 我的服务器为一台全新的centos 7的服务器,所以从 ...
- Openresty最佳案例 | 汇总
转载请标明出处: http://blog.csdn.net/forezp/article/details/78616856 本文出自方志朋的博客 目录 Openresty最佳案例 | 第1篇:Ngin ...
随机推荐
- socket 客户端和服务端通信
客户端要连接服务器:首先要知道服务器的IP地址.而服务器里有很多的应用程序,每一个应用程序对应一个端口号 所以客户端想要与服务器中的某个应用程序进行通信就必须要知道那个应用程序的所在服务器的IP地址, ...
- CSS3 -webkit-transform(元素变换)
CSS3 -webkit-transform(元素变换) -webkit-transform:none | 类型 类型:scale:缩放,1为原始大小.scale(x).正数放大,负数缩小.属性值 ...
- css三角块
html: <div class="angle"></div> css: .angle{ width: 0px; height: 0px; border-b ...
- Visual Studio中C++项目编译常见问题总结
1. 工程引用外部头文件 工程->属性->配置属性->C/C++ ->常规->附加包含目录:输入头文件存放目录 2. 添加lib库引用 添加lib库的路径:工程-> ...
- mysql主从复制报错 :Incorrect usage of DB GRANT and GLOBAL PRIVILEGES
在配置mysql主从复制时,想通过 grant replication slave on bbs.* to 'bbs'@'192.168.1.3' identified by '123456'; 来限 ...
- hello2详解
1.GreetingServlet.java(显示问候页面表单) 此servlet重写该doGet方法,实现GETHTTP方法.servlet显示一个简单的HTML问候表单,其提交按钮就像hello1 ...
- mysql六:mysql内置功能(视图、触发器、事务、存储过程、函数)
一.视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集,可以将该结果集当做表来使用. 通过使用视图可以把查询过程中的 ...
- 洛谷P1351 联合权值(树形dp)
题意 题目链接 Sol 一道很简单的树形dp,然而被我写的这么长 分别记录下距离为\(1/2\)的点数,权值和,最大值.以及相邻儿子之间的贡献. 树形dp一波.. #include<bits/s ...
- CSS基础语法与选择器
CSS基础 语法 : <head> <style type="text/css"> 选择器(即修饰对象){ 修饰属性:属性值; 修饰属性:属性值; } &l ...
- 【代码笔记】Java连连看项目的实现(2)——JTable 、TableModel的使用
博客有时间就写写,所以一篇可能会拆成很多篇,写完后计划再合在一起. 首先肯定是要实现连连看的界面. 先准备连连看要的图片.. “LianLianKan”就是项目名称. 当然,如果小白看我的博客想学到什 ...