Skip to content

Commit e60d666

Browse files
committed
Added local user authentication and user management
1 parent 40e544b commit e60d666

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+1693
-4963
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ nohup.out
88
*.log
99
*.pid
1010
*.tmp
11+
*.db
1112

1213
.idea
1314
.vscode

README.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,19 @@ sessionproviderconfig = "127.0.0.1:6379" # The provider's path or link address
4343
xsrfkey = 4b6774f328ee1a2f24fcb62842fc0cfc # XSRF key
4444
xsrfexpire = 86400 # XSRF expiration time
4545

46-
# User remote authentication API
46+
# User authentication provider, local or remote, default local.
47+
authProvider = local
48+
49+
# Whether to enable User-IP binding to restrict the user to login to the application using a specific IP,
50+
# takes effect when the authProvider is configured to local. once enabled, the manage user needs to
51+
# bind the client IP for each user in the user management page, default false.
52+
ipBinding = false
53+
54+
# User remote authentication API, required when the authProvider is configured to remote.
4755
authAPI = http://127.0.0.1:5000/api/login
4856

49-
# The users who can access control API, default admin
50-
controlUsers = admin;iTraceur;zhaowencheng
57+
# The users who can access user manager page and control API, default admin.
58+
manageUsers = admin;iTraceur;zhaowencheng
5159

5260
# Clinet IP control configuration
5361
[ipControl]

README_CN.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,18 @@ sessionproviderconfig = "127.0.0.1:6379" # Session 存储引擎的路径或链
4040
xsrfkey = 4b6774f328ee1a2f24fcb62842fc0cfc # XSRF key
4141
xsrfexpire = 86400 # XSRF 过期时间
4242

43-
# 远程用户认证接口
43+
# 用户认证提供方, 可设为local或remote, 默认为local
44+
authProvider = local
45+
46+
# 是否开启用户与IP绑定功能来限定用户只能使用特定的IP来登录此应用, 当authProvider配置为local时此配置生效,
47+
# 开启后,管理用户需要在用户管理页面为每个用户绑定客户端IP,默认不开启
48+
ipBinding = false
49+
50+
# 远程用户认证接口, 当authProvider为remote时需要此配置
4451
authAPI = http://127.0.0.1:5000/api/login
4552

46-
# 可访问控制接口的用户,默认为admin
47-
controlUsers = admin;iTraceur;zhaowencheng
53+
# 管理用户,可访问控制接口及管理本地用户,默认为admin
54+
manageUsers = admin;iTraceur;zhaowencheng
4855

4956
# 客户端 IP 访问控制
5057
[ipControl]

conf/app.example.conf

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,21 @@ sessioncookielifetime = 86400
1111
sessionprovider = redis
1212
sessionproviderconfig = "127.0.0.1:6379"
1313

14-
1514
# XSRF configuration
1615
xsrfkey = 4b6774f328ee1a2f24fcb62842fc0cfc
1716
xsrfexpire = 86400
1817

19-
# User authentication login interface
18+
# User authentication provider, local or remote, default local
19+
authProvider = local
20+
21+
# Whether enable binding client ip to the user, needed when authProvider config is local, default false
22+
ipBinding = false
23+
24+
# User remote authentication API, required when authProvider config is remote
2025
authAPI = http://127.0.0.1:5000/api/login
2126

22-
# The users who can access control API
23-
controlUsers = admin;iTraceur;zhaowencheng
27+
# The users who can access control API and manage local users, default admin
28+
manageUsers = admin;iTraceur;zhaowencheng
2429

2530
# Client IP control configuration
2631
[ipControl]

conf/nginx.example.conf

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,22 @@ server {
4141
proxy_cache_key "$http_authorization$cookie_SessionID";
4242
}
4343

44-
location /passport/login {
44+
location /passport {
4545
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
4646
proxy_set_header Host $http_host;
47-
proxy_pass http://auth-backend/passport/login;
47+
proxy_pass http://auth-backend/passport;
4848
}
4949

50-
location /passport/logout {
50+
location /captcha {
5151
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
5252
proxy_set_header Host $http_host;
53-
proxy_pass http://auth-backend/passport/logout;
53+
proxy_pass http://auth-backend/captcha;
5454
}
5555

56-
location /captcha {
56+
location /users {
5757
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
5858
proxy_set_header Host $http_host;
59-
proxy_pass http://auth-backend/captcha;
59+
proxy_pass http://auth-backend/users;
6060
}
6161

6262
location /static {

controllers/auth_proxy.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ type AuthProxyController struct {
99
}
1010

1111
func (this *AuthProxyController) Get() {
12-
this.Ctx.Output.Header("Cache-Control", "no-cache")
13-
uname := this.GetSession("uname")
14-
if uname == nil {
15-
this.Ctx.Abort(401, "401")
16-
return
12+
this.TplName = "index.html"
13+
data := map[string]string{
14+
"title": "Are you ok?",
15+
"p": "I'm ok.",
1716
}
18-
this.Ctx.Output.Body([]byte("ok"))
17+
this.Ctx.Output.Header("Cache-Control", "no-cache")
18+
this.Data["data"] = data
1919
}

controllers/control.go

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,70 +3,66 @@ package controllers
33
import (
44
"fmt"
55
"path/filepath"
6-
"reflect"
7-
"time"
86

97
"github.com/beego/beego/v2/core/logs"
8+
"github.com/beego/beego/v2/core/utils"
109
beego "github.com/beego/beego/v2/server/web"
1110
"github.com/toolkits/file"
1211

1312
"nginx-http-auth/g"
14-
"nginx-http-auth/utils"
1513
)
1614

1715
type ControlController struct {
1816
beego.Controller
1917
}
2018

2119
func (this *ControlController) Get() {
20+
// 获取客户端IP
2221
clientIP := this.Ctx.Input.IP()
23-
logtime := time.Now().Format("02/Jan/2006 03:04:05")
2422

25-
uname := this.GetSession("uname")
26-
if uname == nil {
27-
this.Ctx.Redirect(302, "/passport/login")
23+
// 获取用户Session
24+
username := this.GetSession("uname")
25+
if username == nil {
26+
this.Redirect("/passport/login", 302)
2827
return
2928
}
3029

31-
controlUsers, err := beego.AppConfig.Strings("controlUsers")
30+
// 获取管理用户配置
31+
manageUsers, err := beego.AppConfig.Strings("manageUsers")
3232
if err != nil {
33-
logs.Error(err.Error())
34-
this.Ctx.Output.SetStatus(500)
35-
this.Ctx.WriteString("Internal Server Error")
36-
return
33+
logs.Warn(fmt.Sprintf("%s - get manage users failed: %s", clientIP, err.Error()))
34+
manageUsers = []string{"admin"}
3735
}
38-
if !utils.InSlice(uname.(string), controlUsers) {
39-
logs.Debug(uname.(string), controlUsers, controlUsers[0], reflect.TypeOf(controlUsers[0]))
40-
this.Ctx.Output.SetStatus(401)
41-
this.Ctx.Output.Body([]byte("Not Allowed"))
42-
return
36+
// 管理用户校验
37+
if !utils.InSlice(username.(string), manageUsers) {
38+
logs.Warn(fmt.Sprintf("%s - %s - access to control API was denied", clientIP, username))
39+
this.Abort("403")
4340
}
4441

42+
// 获取管理类型
4543
control := this.Ctx.Input.Param(":control")
4644
switch control {
47-
case "version":
48-
this.Ctx.Output.Body([]byte(g.VERSION))
49-
case "health":
50-
this.Ctx.Output.Body([]byte("ok"))
51-
case "config":
45+
case "version": // 获取版本
46+
_ = this.Ctx.Output.Body([]byte(g.VERSION))
47+
case "health": // 探活
48+
_ = this.Ctx.Output.Body([]byte("ok"))
49+
case "config": // 获取配置信息
5250
var json map[string]interface{}
5351
err = beego.AppConfig.Unmarshaler("", &json)
5452
if err != nil {
55-
logs.Error(err.Error())
56-
this.Ctx.Output.SetStatus(500)
57-
this.Ctx.WriteString("Internal Server Error")
58-
return
53+
logs.Error(fmt.Sprintf("%s - get config info failed: %s", clientIP, err.Error()))
54+
this.Abort("550")
5955
}
6056
this.Data["json"] = json
61-
this.ServeJSON()
62-
case "reload":
57+
_ = this.ServeJSON()
58+
case "reload": // 重新加载配置
6359
err := beego.LoadAppConfig("ini", filepath.Join(file.SelfDir(), "conf/app.conf"))
6460
if err != nil {
65-
logs.Error(fmt.Sprintf("%s - - [%s] Config reload failed: %s", clientIP, logtime, err.Error()))
66-
this.Ctx.Output.Body([]byte("config reload failed"))
61+
logs.Error(fmt.Sprintf("%s - config reload failed: %s", clientIP, err.Error()))
62+
_ = this.Ctx.Output.Body([]byte("config reload failed"))
6763
} else {
68-
logs.Notice(fmt.Sprintf("%s - - [%s] Config Reloaded", clientIP, logtime))
69-
this.Ctx.Output.Body([]byte("config reloaded"))
64+
logs.Info(fmt.Sprintf("%s - config Reloaded", clientIP))
65+
_ = this.Ctx.Output.Body([]byte("config reloaded"))
7066
}
7167
}
7268
}

controllers/default.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package controllers
22

33
import (
4+
"fmt"
45
beego "github.com/beego/beego/v2/server/web"
56
"nginx-http-auth/g"
67
)
@@ -10,10 +11,10 @@ type MainController struct {
1011
}
1112

1213
func (this *MainController) Get() {
13-
uname := this.GetSession("uname")
14-
if uname == nil {
15-
this.Ctx.Redirect(302, "/passport/login")
16-
return
14+
this.TplName = "index.html"
15+
data := map[string]string{
16+
"title": "nginx-http-auth",
17+
"p": fmt.Sprintf("Version: %s", g.VERSION),
1718
}
18-
this.Ctx.Output.Body([]byte("nginx-http-auth, version " + g.VERSION))
19+
this.Data["data"] = data
1920
}

controllers/error.go

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,80 @@ type ErrorController struct {
88
beego.Controller
99
}
1010

11+
func (this *ErrorController) Prepare() {
12+
this.Layout = "main-simple.html"
13+
this.LayoutSections = make(map[string]string)
14+
this.LayoutSections["HtmlHead"] = "deny-head.html"
15+
}
16+
1117
func (this *ErrorController) Error401() {
12-
this.Data["content"] = "限制访问,请求被拒绝"
13-
this.TplName = "deny.tpl"
18+
this.Data["title"] = "未授权页面"
19+
this.Data["content"] = "未登录或认证状态失效"
20+
this.TplName = "deny.html"
1421
}
1522

1623
func (this *ErrorController) Error403() {
24+
this.Data["title"] = "拒绝访问"
25+
this.Data["content"] = "限制访问,请求被拒绝"
26+
this.TplName = "deny.html"
27+
}
28+
29+
func (this *ErrorController) Error404() {
30+
this.Data["title"] = "Ooops!"
31+
this.Data["content"] = "页面未找到"
32+
this.TplName = "deny.html"
33+
}
34+
35+
func (this *ErrorController) Error405() {
36+
this.Data["title"] = "非法请求"
37+
this.Data["content"] = "不允许的请求方法"
38+
this.TplName = "deny.html"
39+
}
40+
41+
func (this *ErrorController) Error417() {
42+
this.Data["title"] = "非法请求"
43+
this.Data["content"] = "XSRF校验失败"
44+
this.TplName = "deny.html"
45+
}
46+
47+
func (this *ErrorController) Error422() {
48+
this.Data["title"] = "非法请求"
49+
this.Data["content"] = "请求未提交XSRF参数"
50+
this.TplName = "deny.html"
51+
}
52+
53+
func (this *ErrorController) Error450() {
54+
this.Data["title"] = "拒绝访问"
55+
this.Data["content"] = "IP不匹配,请求被拒绝"
56+
this.TplName = "deny.html"
57+
}
58+
59+
func (this *ErrorController) Error451() {
60+
this.Data["title"] = "拒绝访问"
61+
this.Data["content"] = "限制IP访问,请求被拒绝"
62+
this.TplName = "deny.html"
63+
}
64+
65+
func (this *ErrorController) Error452() {
66+
this.Data["title"] = "拒绝访问"
1767
this.Data["content"] = "当前时间段不允许访问"
18-
this.TplName = "deny.tpl"
68+
this.TplName = "deny.html"
69+
}
70+
71+
func (this *ErrorController) Error453() {
72+
this.Data["title"] = "拒绝访问"
73+
this.Data["content"] = "限制用户访问,请求被拒绝"
74+
this.TplName = "deny.html"
75+
}
76+
77+
func (this *ErrorController) Error500() {
78+
this.Data["title"] = "服务异常"
79+
this.Data["content"] = "服务器内部错误"
80+
this.TplName = "deny.html"
81+
}
82+
83+
func (this *ErrorController) Error550() {
84+
this.Data["title"] = "服务异常"
85+
this.Data["content"] = "服务未正确配置"
86+
this.TplName = "deny.html"
1987
}

0 commit comments

Comments
 (0)