基于openResty+lua的权限校验

2.1k 词

  之前在这篇文章想进openResty的坑里说要做个和权限相关的大实例,这篇算给做的东西一个详细点的README,代码已经丢到github
  之前是在Google随便搜了shiro和openResty的关键字,看到了这个,其实他的权限校验是在后台用go语言做的,nginx只是在前面做了个转发功能,这是我给作者提的issue,我是自己用lua做了逻辑   

大体实现功能

请求过来时统一先处理,在access_by_lua阶段执行权限校验。每次先到redis取权限,取不到则连mysql取,再把结果填到redis里(模拟,设置了3秒过期),然后调本地服务看是否通过权限校验,通过之后再进行请求的路由分发,不通过直接返403给客户端

模块

关于shiro

  官网,java的一个权限框架。可以做粒度很细的权限,比方你要使用3号打印机,可以用这样的形式printer:query:3来表达这个资源,printer是model,query是action,就是传统的增删改查的动作,3是这个model的主键。在java里可以用这样的注解来做权限校验@RequiresPermissions(“printer:query:3”)。
  这是最细的情况,比方printer:*则可以表示这个用户对所有打印机有所有的增删改查的权限,printer:query:*可以表达用户对所有的打印机有读的权限
  好吧就说到这吧

在java后端模拟shiro权限校验,供openResty调用

  由于lua写解析太复杂了,相当于要自己写一个解析的工具类,处理比方拥有这个printer:*这个权限是包含了printer:query:3这个权限这样的功能,本着不重复造轮子的原则,我在本地搭了个服务供openresty直接调用,接收两个数组,一个是请求的权限的集合,一个是用户已有权限的集合,利用shiro的WildcardPermission类进行处理
  一小段java代码,implies方法就是这个解析的过程
  用伪码表达的话,如果权限1包含权限2,则 权限1.implies(权限2) 会返回true

public boolean isPermitted(WildcardPermission[] reqs, WildcardPermission[] hasPers) {
  boolean flag = true;
  for (WildcardPermission req : reqs) {
    flag = false;
    for (WildcardPermission hasPer : hasPers) {
      if (hasPer.implies(req)) {
          flag = true;
          break ;
      }
    }
  }
  return flag;
}

  涉及ngx.location.capture去调本地的服务

redis取权限,取不到则读mysql

关于openResty+lua 项目的文件组织和请求路由的问题

  这个问题有两种处理,我在openResty china里发过提问帖

在location里通过url分发类似这样

    location ~ '^/([a-z]+)/(update|create|delete|query)/?(d*)$' {
      content_by_lua_file "lua/$1.lua";
    }

如果用访问地址”localhost:6699/user/query/33”,会被lua/user.lua这个文件处理,可以在这个文件里再去细化业务

另一种是请求分发直接在一个lua文件里做

  使用了lua-resty-route这个组件做请求路由分发到不同的业务类做处理

路由请求这个功能不算是权限系统里的部分,但由于自己是openResty新手,没做过实际项目,而路由分发这种肯定是每个项目的基础功能必不可少,所以算作是打个基础

路由请求这块参考过的资料包括但不限于如下

后续可能会做的功能

  • 无则跳转至无权限提示页,面涉及用resty-template渲页面,主要是熟悉下
  • 加入session模块,用户过来先判断session合法性,取用户身份,再校验权限,使用resty-session,现阶段在请求头带个user_name的域模拟用户身份
  • 抽象化到所有需要资源请求释放的例子,数据库、mysql、线程池等,尝试自己写一个封装resty-mysql的工具类