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)endlocal 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_idres, 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) doif name == "permission" thentable.insert(permissions, 1, value)end  end  end  return permissions
endlocal _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 = 6379local 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 thenreturn falseend--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--endreturn red
endfunction has_token(token)local red = connect()if red == false thenreturn falseendlocal res, err = red:get(token)if not res thenreturn falseendclose_redis(red)  return true
endfunction set_permissions(user_id,permissions)if (permissions==null) or( permissions==ngx.null) thenreturn falseend local str = cjson.encode(permissions)  ngx.log(ngx.ERR,"set redis p:"..str)local red=connect()if red== false thenreturn falseendlocal ok, err = red:set(user_id,str)if not ok thenreturn falseendreturn true
endfunction get_permissions(user_id)local red=connect()if red== false thenreturn falseendlocal res, err = red:get(user_id)if (not res) or (res == ngx.null) thenreturnend ngx.log(ngx.ERR,"get redis p:"..res);local permissions=cjson.decode(res)  return permissions
endfunction 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 thenngx.say("ok")
elsengx.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模块工具类相关推荐

  1. Openresty最佳案例 | 第4篇:OpenResty常见的api

    获取请求参数 vim  /usr/example/example.conf location /lua_var {default_type 'text/plain';content_by_lua_bl ...

  2. Openresty最佳案例 | 第1篇:Nginx介绍

    Nginx 简介 Nginx是一个高性能的Web 服务器,同时是一个高效的反向代理服务器,它还是一个IMAP/POP3/SMTP 代理服务器. 由于Nginx采用的是事件驱动的架构,能够处理并发百万级 ...

  3. Openresty最佳案例 | 第9篇:Openresty实现的网关权限控制

    简介 采用openresty 开发出的api网关有很多,比如比较流行的kong.orange等.这些API 网关通过提供插件的形式,提供了非常多的功能.这些组件化的功能往往能够满足大部分的需求,如果要 ...

  4. Openresty最佳案例 | 第7篇: 模块开发、OpenResty连接Redis

    Lua模块开发 在实际的开发过程中,不可能把所有的lua代码写在一个lua文件中,通常的做法将特定功能的放在一个lua文件中,即用lua模块开发.在lualib目录下,默认有以下的lua模块. lua ...

  5. Openresty最佳案例 | 第5篇:http和C_json模块

    http客户端 Openresty没有提供默认的Http客户端,需要下载第三方的http客户端. 下载lua-resty-http到lualib目录下,使用以下的命令下载: cd /usr/examp ...

  6. Openresty最佳案例 | 第3篇:Openresty的安装

    我的服务器为一台全新的centos 7的服务器,所以从头安装openresty,并记录了安装过程中出现的问题,以及解决办法. 1.首先安装openresty cd /usr mkdir servers ...

  7. Fresco图片加载框架的介绍,相关开源库以及工具类的封装

    Fresco图片加载框架的介绍,相关开源库以及工具类的封装 本文已授权微信公众号:鸿洋(hongyangAndroid)在微信公众号平台原创首发. 简介 Fresco 是Facebook开源的安卓上的 ...

  8. Openresrt最佳案例 | 第2篇:Lua入门

    什么是lua Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能. Lua 是巴西里约热内卢天主教大学(Po ...

  9. Openresrt最佳案例

    第1篇:Nginx介绍 Nginx是一个高性能的Web 服务器,同时是一个高效的反向代理服务器,它还是一个IMAP/POP3/SMTP 代理服务器. 由于Nginx采用的是事件驱动的架构,能够处理并发 ...

最新文章

  1. 一文读懂GoogLeNet神经网络 | CSDN博文精选
  2. eclipse中检查项目生成.class文件的地址
  3. mysql如何实现acid中的a_MySQL如何实现事务的ACID
  4. 好好学一遍JavaScript 笔记(一)
  5. STM32H743+Keil-将变量定义到指定内存
  6. flutter 微信语言选择_Flutter/dart聊天实例|仿微信界面|红包|朋友圈
  7. java查询到更新之前的数据_Java对数据库的查询和更新操作详解
  8. Undefined symbols for architecture xxx
  9. 不好意思,观察者模式跟发布订阅模式就是不一样
  10. 博为峰Java技术文章 ——JavaEE Hibernate HQL条件查询
  11. vscode we cannot connect_秋季常规赛分秒必争,PC BET直播:TES能否拿下西安WE
  12. java8中lambda的用法(map转list,list转map等等)
  13. 求二元一次方程 的解 C语言
  14. 程序员必备十款开发工具,会用的可以召唤神龙了!
  15. LocalSend 电脑和手机互传软件教程解答手机端无法搜索到电脑的解决方案
  16. 无法启动计算机的杀毒软件,电脑中毒杀毒软件无法启动任务管理器也被禁用怎么办?...
  17. 多链钱包鼻祖bitpay 10.0.1最新版官方版下载和使用方法
  18. java毕业设计开题报告怎么写 如何写好一篇论文开题报告
  19. Power oj 2781: 上决╇ф的黑科技 (任意模数NTT|拆系数FFT)
  20. RHEL5.5下载地址及安装序列号

热门文章

  1. react遇到的各种坑
  2. Build SSCLI20 under VS2008 full Document (完全手册)
  3. web service 项目 和 普通 web项目 的 区别
  4. 九宫格抽奖转盘源码分析
  5. NEWS - InstallShield 2013 SP1发布
  6. C#操作excel(多种方法比较)
  7. 自定义Linq的Distinct
  8. 技术图文:Matlab向量 VS. Python列表
  9. 【机器学习】基于人工鱼群算法的多元非线性函数寻优
  10. Matlab编程与数据类型 -- 数据类型概述