Luci的多级用户管理

来源:互联网 发布:琅琊榜出口数据 编辑:程序博客网 时间:2024/05/01 22:54

目录

  • 目录
  • Luci的多级用户管理
    • 实现方法
      • indexlua
      • dispatcherlua
      • servicectllua
      • controllermultiUserlua
      • modelcbimultiUserlua
      • 防止用户删除本用户操作cbilua
    • 思路
    • 想法

Luci的多级用户管理

Openwrt的web管理是用luci来实现的,但是luci本身不支持多级用户管理,并实现不同用户显示不同的界面。因为工作需要所以花了点时间把这个功能完成了。

实现方法

看了网上的一些文档,基本实现的都是把root改成别的用户登录,但是都没有实现多级用户的管理。根据这些文档,自己又做了些更改,主要更改的文件有:
/user/lib/lua/luci/controller/admin/index.lua/user/lib/lua/luci/dispatcher.lua/user/lib/lua/luci/controller/admin/servicectl.lua
添加的文件有:
/user/lib/lua/luci/model/cbi/multiUser.lua/user/lib/lua/luci/controller/multiUser.lua

index.lua

 function index()+       local fs = require "nixio.fs"+       local UCI = require("luci.model.uci")+       local uci     = UCI.cursor()+       local multiUser = { }+        local root = node()        if not root.target then            root.target = alias("admin")@@ -14,7 +19,19 @@ function index()        page.target  = firstchild()        page.title   = _("Administration")        page.order   = 10-       page.sysauth = "root"+       page.sysauth = { "root" }+       if fs.access("/etc/config/multiUser") then+           multiUser = uci:get_all("multiUser")+               for k, v in pairs(multiUser) do+                       if type(v) == "table" then+                               for j, l in pairs(v) do+                                       if j == "user" then+                                               table.insert(page.sysauth, l)+                                       end+                               end+                       end+               end+       end
  • page.sysauth的属性是整个页面需要验证的的用户名,当登录的用户名不存在这个表里面,那么luci将进入一个空的界面。
  • uci:get_all(“multiUser”)是获取/etc/config/multiUser下的配置在uci缓存里面的内容,并以表的形式放入到multiUser变量里面。
    注:这个函数获是用uci方式获取的,所以表的结果并不一定等于配置文件的内容。通过uci set命令可以设置配置文件让结果不相等。所以luci界面上应该禁止删除本用户,防止出现删除后配置文件还没保存,但是已经登录不上去的情况,这个下面的代码会有说到
  • 功能说明:根据multiUser的配置文件获取所有用户配置的用户名然后追加到page.syauth表里面,让luci的系统验证支持这些用户名。

dispatcher.lua

@@ -108,20 +108,86 @@ end function authenticator.htmlauth(validator, accs, default)        local user = http.formvalue("luci_username")        local pass = http.formvalue("luci_password")+       local user_table = ""+       local pass_table = ""+       local level_table = ""+       local fs = require "nixio.fs"+       local UCI = require("luci.model.uci")+       local uci     = UCI.cursor()+       local multiUser = { }+       local file=io.open("/var/luci/shadow","w")+       +       if fs.access("/etc/config/multiUser") then+               multiUser = uci:get_all("multiUser")+               for k, v in pairs(multiUser) do+                       if type(v) == "table" then+                               user_table = ""+                               pass_table = ""+                               level_talbe = ""+                               for j, l in pairs(v) do+                                       if j == "user" then+                                               user_table = l+                                       end+                                       if j == "pwd" then+                                               pass_table = l+                                       end+                                       if j == "level" then+                                               level_table = l+                                       end+                               end+                               if user_table == user and pass_table == pass then+                                       if not file then+                                               luci.util.exec("mkdir -p /var/luci/")+                                               file = io.open("/var/luci/shadow", "w")+                                       end+                                       file:write(user)+                                       file:write("\n")+                                       file:write(level_table)+                                       file:close()+                                       return user+                               end+                       end+               end+       end-       if user and validator(user, pass) then+       --[[ if user and validator(user, pass) then                file=io.open("/tmp/current_user","w")                file:write(user)                file:close()                return user-       end+       end ]]--
  • 改变用户名密码的判断方式,如果仍想用系统的用户名密码,那么需要写一个程序在multiUser配置变化时后执行adduer命令,把用户名添加到系统即可
  • 把当前用户写到文件里面的作用是在luci中防止本用户删除本用户的操作
        if context.urltoken.stok then                context.urltoken.stok = nil@@ -343,6 +408,62 @@ function dispatch(request)                                authen = function() return eu end                        end                end+                       --[[+                       context.tree.nodes.admin.nodes.status.title=""+                       context.tree.nodes.admin.nodes.system.title=""+                       context.tree.nodes.admin.nodes.services.title=""+                       context.tree.nodes.admin.nodes.network.title=""+                       ]]--+                       if level == "1" then+                               --context.tree.nodes.admin.nodes.services.title=""+                       elseif level == "2" then+                               for j, k in pairs(context.tree.nodes.admin.nodes.network.nodes) do+                                       if j == "wireless"+                                               or j == "hosts"+                                               --or j == "firewall"+                                               or j == "diagnostics"+                                               or j == "dhcp"+                                               or j == "routes"+                                               then+                                                       k.title=""+                                                       k.leaf=true+                                                       k.target=""+                                       end+                               end+                               context.tree.nodes.admin.nodes.services.title=""+                               context.tree.nodes.admin.nodes.services.leaf=true+                               for j, k in pairs(context.tree.nodes.admin.nodes.system.nodes) do+                                       if j == "admin"+                                               or j == "system"+                                               or j == "packages"+                                               or j == "startup"+                                               or j == "leds"+                                               or j == "multiUser"+                                               or j == "crontab"+                                               or j == "fstab"+                                               then+                                                       k.title=""+                                                       k.leaf=true+                                                       k.target=""+                                       end+                               end+                               for j, k in pairs(context.tree.nodes.admin.nodes.status.nodes) do+                                       if j == "dmesg"+                                               or j == "routes"+                                               or j == "iptables"+                                               or j == "realtime"+                                               or j == "syslog"+                                               or j == "processes"+                                               then+                                                       k.title=""+                                                       k.leaf=true+                                                       k.target=""+                                       end+                               end+                        end
  • 隐藏页面的关键是把page.target 和page.title属性写成空,page.leaf属性官方文档上写的是防止更新的意思,我也没怎么搞明白,如果有人明白的请留言给我。
  • 注释的内容显示了所有能显示的page的表。

servicectl.lua

 module("luci.controller.admin.servicectl", package.seeall) function index()-       entry({"servicectl"}, alias("servicectl", "status")).sysauth = "root"+       entry({"servicectl"}, alias("servicectl", "status"))
  • 因为是多级用户管理,所以用户名不是单个。只需要顶层的表admin的sysauth属性是正确的即可。

controller/multiUser.lua

@@ -0,0 +1,12 @@+module("luci.controller.multiUser", package.seeall)++++function index()+       local fs = require "nixio.fs"+       if fs.access("/etc/config/multiUser") then+               entry({"admin", "system","multiUser"}, cbi("multiUser"), translate("Multi-leve User Configuration"), 12)+       end++end+

model/cbi/multiUser.lua

+--m = Map("multiUser", translate("<abbr title=\"Light Emitting Diode\">LED</abbr> Configuration"), translate("Customizes the behaviour of the device <abbr title=\"Light Emitting+m = Map("multiUser", translate("Multi-leve User Configuration"), translate("Multi-level user management"))++s = m:section(TypedSection, "multiUser", "")+s.anonymous = true+s.addremove = true+s.template = "cbi/tblsection"++user = s:option(Value, "user", translate("Username"))+user.rmempt=true++pwd = s:option(Value, "pwd", translate("Password"))+pwd.password = true+pwd.rmempt=true++level = s:option(ListValue, "level", translate("Level"))+level:value("1", translate("Administrator"))+level:value("2", translate("Ordinary User"))++function m.before_save(map)+        local x = luci.http.formvalue(section)+        local name = {}+        local i = 0+        for k, v in pairs(x) do+                if string.find(k, "multiUser.+user") ~= nil then+                        local t = type(v)+                        if t ~= 'table' then+                                name[i] = v+                                i = i + 1+                        end+                end+        end+        for k, v in pairs(name) do+                for k_inter, v_inter in pairs(name) do+                        if k ~= k_inter then+                                if v == v_inter then+                                        m.message = translate("User name is conflict!")+                                        return false+                                end+                        end+                end+        end+        return true++end++++return m
  • s.template里面指定了显示的格式为用户名和密码同一列的格式
  • s.addremove=true显示了添加和删除按钮
  • s.anonymous=true是隐藏了标题
  • m.before_save(map)这个函数需要在cbi.lua声明使用,代码如下:
        Node.parse(self, ...)        if self.save then +                local run_hooks_return = +self:run_hooks("before_save")+                if run_hooks_return ~= nil then+                        if run_hooks_return == false then                 +                                return+                        end            +                end  

防止用户删除本用户操作:cbi.lua

@@ -1156,16 +1165,33 @@ function TypedSection.depends(self, option, value) end function TypedSection.parse(self, novld)+        local fs = require "nixio.fs"+        local UCI = require("luci.model.uci")+        local uci     = UCI.cursor()+        local multiUser = { }++        if fs.access("/etc/config/multiUser") then+                multiUser = uci:get_all("multiUser")+       end        if self.addremove then                -- Remove                local crval = REMOVE_PREFIX .. self.config                local name = self.map:formvaluetable(crval)                for k,v in pairs(name) do+                       local deluser = ""+                       local cuser = luci.util.exec("cat /tmp/luci/shadow | head -1 | tr -d '\n' 2> /dev/null")                        if k:sub(-2) == ".x" then                                k = k:sub(1, #k - 2)                        end+                       for a, b in pairs(multiUser) do+                               if a == k then+                                       deluser = b.user+                               end+                       end                        if self:cfgvalue(k) and self:checkscope(k) then-                               self:remove(k)+                               if deluser ~= cuser then+                                       self:remove(k)+                               end                        end                end        end
  • 禁止删除本用户的操作,当点击删除TypedSection类型的section的按钮时,会执行这个函数。

思路

整体的思路很简单,就是当用户登录时判断这个用户的等级,如果等级为2,那么把一些页面的3个属性值改掉。关键点:动态的实现系统sysauth的值动态改变

想法

初次写博客,如有错误请指正。
1 0
原创粉丝点击