Franz`s blog

Openresty 实现 WebDAV 功能 ,并且实现在 WebDAV 下多用户认证以及访问目录控制 - 2

关于openresty-dav的编译以及简单的webdav部署请看上文

在上文中我们编译了带WebDAV功能的Openresty,并且实现了简单的WebDAV功能

Openresty配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
location ~ /dav/(?<bucket_id>\d+)/(?<sub_path>.*) {
set $user_path "";
set $bucket_id $1;
# 临时文件夹
client_body_temp_path /toss/tmp;
# webdav 支持的方式
dav_methods PUT DELETE MKCOL COPY MOVE;
# webdav 插件支持的请求方式
dav_ext_methods PROPFIND OPTIONS LOCK UNLOCK;

create_full_put_path on;
# 访问权限
dav_access user:rw group:rw all:r;

#禁止创建文件夹
if ($request_method = MKCOL) {
return 405;
}
# 网页自动索引
autoindex on;
# 基于 http basic 的认证
auth_basic "Authorized Users Only";
# 权限控制和 user_path 控制
access_by_lua_file lua/webdav_auth.lua;
# 设置目录
alias $user_path/$sub_path;
}

可以通过access_by_lua_file文件动态控制webdav访问的目录以及用户认证。

在lua file中设置$user_path以及$sub_path变量

通过http basic进行用户的认证

lua脚本编写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
local mysql = require("resty.mysql")
local resty_sha1 = require("resty.sha1")
local str = require("resty.string")

local headers = ngx.req.get_headers()
local authorization = headers["Authorization"]

local salt = "qefd1y098ehudi"


local db, err = mysql:new()
if not db then
ngx.log(ngx.ERR, "failed to instantiate mysql: ", err)
return
end
db:set_timeout(1000)
local ok, err, errno, sqlstate = db:connect {
host = "db",
port = 3306,
database = "dbname",
user = "root",
password = "pwd"
}
if not ok then
ngx.log(ngx.ERR, "failed to connect: ", err, ": ", errno, " ", sqlstate)
return
end
local function close_db(db)
if not db then
return
end
db:close()
end

local function check(username, password)
local sha1 = resty_sha1:new()
sha1:update(password)
sha1:update(salt)
local digest = sha1:final()
local pwd = tostring(str.to_hex(digest))
local quoted = ngx.quote_sql_str(tostring(username))
local sql = "SELECT count(*) sum FROM `tb_sysuser` where `username` = " ..quoted.. " and `password` = '" ..pwd .. "'"
ngx.log(ngx.ALERT,"sql = " .. sql)
res, err, errno, sqlstate = db:query(sql)

if not res then
ngx.log(ngx.ALERT,"database Error \n" .. err)
close_db(db)
return
end

for i, row in ipairs(res) do
for name, value in pairs(row) do
if name == "sum" then
ngx.log(ngx.ALERT, "value = " .. value)
return value == "1"
end
end
end

return false

end

local function checkPriviledge(username)
local quoted = ngx.quote_sql_str(tostring(username))

local sql = "select privilege from tb_bucket_privilege where bid = "..ngx.var.bucket_id.." and uid = (SELECT id from tb_sysuser where username = "..quoted.." )"

ngx.log(ngx.ALERT,"sql = " .. sql)

res, err, errno, sqlstate = db:query(sql)

if not res then
ngx.log(ngx.ALERT,"database Error \n" .. err)
close_db(db)
return
end

for i, row in ipairs(res) do
for name, value in pairs(row) do
if name == "privilege" then
close_db(db)
ngx.log(ngx.ALERT, "value = " .. value)
return value == "rw"
end
end
end

return false
end

local function fail()
ngx.header["WWW-Authenticate"] = 'Basic realm="Restricted Area"'
ngx.exit(ngx.HTTP_UNAUTHORIZED)
end


if authorization then
local encoded = authorization:sub(7)
local decoded = ngx.decode_base64(encoded)
local username, password = decoded:match("([^:]*):(.*)")
ngx.log(ngx.ALERT, username .. ":" .. password)
if check(username, password) then
ngx.req.set_header("X-User", username)
local readlPath = "/toss/" .. ngx.var.bucket_id
ngx.log(ngx.ALERT,readlPath)
if checkPriviledge(username) then
ngx.var.user_path = readlPath
else
fail()
end
else
fail()
end
else
fail()
end

通过上述lua脚本控制访问权限和访问目录

注意上面lua脚本默认的访问根目录是 /toss/

通过访问mysql数据库校验权限