From 6cfa92944c97ab239da2e5f6a5a3eddc942a7941 Mon Sep 17 00:00:00 2001 From: lanrenwo Date: Fri, 13 Jan 2023 14:14:47 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=90=8E=E5=8F=B0?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=99=BB=E5=BD=95=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/admin/api_group.go | 27 ++++++++++ server/admin/server.go | 1 + server/dbdata/group.go | 15 ++++++ server/dbdata/group_test.go | 15 +++--- server/dbdata/user_test.go | 15 +++--- server/dbdata/userauth_ldap.go | 27 ++++++---- web/src/pages/group/List.vue | 95 +++++++++++++++++++++++++++++++--- 7 files changed, 164 insertions(+), 31 deletions(-) diff --git a/server/admin/api_group.go b/server/admin/api_group.go index 8f9a01d..44522a9 100644 --- a/server/admin/api_group.go +++ b/server/admin/api_group.go @@ -118,3 +118,30 @@ func GroupDel(w http.ResponseWriter, r *http.Request) { } RespSucess(w, nil) } + +func GroupAuthLogin(w http.ResponseWriter, r *http.Request) { + type AuthLoginData struct { + Name string `json:"name"` + Pwd string `json:"pwd"` + Auth map[string]interface{} `json:"auth"` + } + + body, err := io.ReadAll(r.Body) + if err != nil { + RespError(w, RespInternalErr, err) + return + } + defer r.Body.Close() + v := &AuthLoginData{} + err = json.Unmarshal(body, &v) + if err != nil { + RespError(w, RespInternalErr, err) + return + } + err = dbdata.GroupAuthLogin(v.Name, v.Pwd, v.Auth) + if err != nil { + RespError(w, RespInternalErr, err) + return + } + RespSucess(w, "ok") +} diff --git a/server/admin/server.go b/server/admin/server.go index 2f0bae0..2db6d0c 100644 --- a/server/admin/server.go +++ b/server/admin/server.go @@ -71,6 +71,7 @@ func StartAdmin() { r.HandleFunc("/group/detail", GroupDetail) r.HandleFunc("/group/set", GroupSet) r.HandleFunc("/group/del", GroupDel) + r.HandleFunc("/group/auth_login", GroupAuthLogin) r.HandleFunc("/statsinfo/list", StatsInfoList) diff --git a/server/dbdata/group.go b/server/dbdata/group.go index e08c286..e664aeb 100644 --- a/server/dbdata/group.go +++ b/server/dbdata/group.go @@ -225,6 +225,21 @@ func SetGroup(g *Group) error { return err } +func GroupAuthLogin(name, pwd string, authData map[string]interface{}) error { + g := &Group{Auth: authData} + authType := g.Auth["type"].(string) + if _, ok := authRegistry[authType]; !ok { + return errors.New("未知的认证方式: " + authType) + } + auth := makeInstance(authType).(IUserAuth) + err := auth.checkData(g.Auth) + if err != nil { + return err + } + err = auth.checkUser(name, pwd, g) + return err +} + func parseIpNet(s string) (string, *net.IPNet, error) { ip, ipNet, err := net.ParseCIDR(s) if err != nil { diff --git a/server/dbdata/group_test.go b/server/dbdata/group_test.go index b4b26f9..0d64c86 100644 --- a/server/dbdata/group_test.go +++ b/server/dbdata/group_test.go @@ -46,13 +46,14 @@ func TestGetGroupNames(t *testing.T) { authData = map[string]interface{}{ "type": "ldap", "ldap": map[string]interface{}{ - "addr": "192.168.8.12:389", - "tls": true, - "bind_name": "userfind@abc.com", - "bind_pwd": "afdbfdsafds", - "base_dn": "dc=abc,dc=com", - "search_attr": "sAMAccountName", - "member_of": "cn=vpn,cn=user,dc=abc,dc=com", + "addr": "192.168.8.12:389", + "tls": true, + "bind_name": "userfind@abc.com", + "bind_pwd": "afdbfdsafds", + "base_dn": "dc=abc,dc=com", + "object_class": "person", + "search_attr": "sAMAccountName", + "member_of": "cn=vpn,cn=user,dc=abc,dc=com", }, } g7 := Group{Name: "g7", ClientDns: []ValData{{Val: "114.114.114.114"}}, Auth: authData} diff --git a/server/dbdata/user_test.go b/server/dbdata/user_test.go index d9f3a69..fea4735 100644 --- a/server/dbdata/user_test.go +++ b/server/dbdata/user_test.go @@ -70,13 +70,14 @@ func TestCheckUser(t *testing.T) { authData = map[string]interface{}{ "type": "ldap", "ldap": map[string]interface{}{ - "addr": "192.168.8.12:389", - "tls": true, - "bind_name": "userfind@abc.com", - "bind_pwd": "afdbfdsafds", - "base_dn": "dc=abc,dc=com", - "search_attr": "sAMAccountName", - "member_of": "cn=vpn,cn=user,dc=abc,dc=com", + "addr": "192.168.8.12:389", + "tls": true, + "bind_name": "userfind@abc.com", + "bind_pwd": "afdbfdsafds", + "base_dn": "dc=abc,dc=com", + "object_class": "person", + "search_attr": "sAMAccountName", + "member_of": "cn=vpn,cn=user,dc=abc,dc=com", }, } g3 := Group{Name: group3, Status: 1, ClientDns: dns, RouteInclude: route, Auth: authData} diff --git a/server/dbdata/userauth_ldap.go b/server/dbdata/userauth_ldap.go index 9d25783..e7a5f1a 100644 --- a/server/dbdata/userauth_ldap.go +++ b/server/dbdata/userauth_ldap.go @@ -15,13 +15,14 @@ import ( ) type AuthLdap struct { - Addr string `json:"addr"` - Tls bool `json:"tls"` - BindName string `json:"bind_name"` - BindPwd string `json:"bind_pwd"` - BaseDn string `json:"base_dn"` - SearchAttr string `json:"search_attr"` - MemberOf string `json:"member_of"` + Addr string `json:"addr"` + Tls bool `json:"tls"` + BindName string `json:"bind_name"` + BindPwd string `json:"bind_pwd"` + BaseDn string `json:"base_dn"` + ObjectClass string `json:"object_class"` + SearchAttr string `json:"search_attr"` + MemberOf string `json:"member_of"` } func init() { @@ -40,7 +41,7 @@ func (auth AuthLdap) checkData(authData map[string]interface{}) error { return errors.New("LDAP的服务器地址(含端口)填写有误") } if auth.BindName == "" { - return errors.New("LDAP的管理员账号不能为空") + return errors.New("LDAP的管理员 DN不能为空") } if auth.BindPwd == "" { return errors.New("LDAP的管理员密码不能为空") @@ -48,6 +49,9 @@ func (auth AuthLdap) checkData(authData map[string]interface{}) error { if auth.BaseDn == "" || !ValidateDN(auth.BaseDn) { return errors.New("LDAP的Base DN填写有误") } + if auth.ObjectClass == "" { + return errors.New("LDAP的用户对象类填写有误") + } if auth.SearchAttr == "" { return errors.New("LDAP的用户唯一ID不能为空") } @@ -94,9 +98,12 @@ func (auth AuthLdap) checkUser(name, pwd string, g *Group) error { } err = l.Bind(auth.BindName, auth.BindPwd) if err != nil { - return fmt.Errorf("%s LDAP 管理员账号或密码填写有误 %s", name, err.Error()) + return fmt.Errorf("%s LDAP 管理员 DN或密码填写有误 %s", name, err.Error()) } - filterAttr := "(objectClass=person)" + if auth.ObjectClass == "" { + auth.ObjectClass = "person" + } + filterAttr := "(objectClass=" + auth.ObjectClass + ")" filterAttr += "(" + auth.SearchAttr + "=" + name + ")" if auth.MemberOf != "" { filterAttr += "(memberOf:=" + auth.MemberOf + ")" diff --git a/web/src/pages/group/List.vue b/web/src/pages/group/List.vue index 1b4b816..e316e04 100644 --- a/web/src/pages/group/List.vue +++ b/web/src/pages/group/List.vue @@ -251,7 +251,7 @@ - + @@ -259,9 +259,12 @@ - + + + + - + @@ -359,13 +362,34 @@ - 保存 - 取消 + + 测试登录 + + 保存 + 取消 - + + + + + + + + + + + 登录 + 取 消 + + @@ -399,6 +423,7 @@ export default { addr:"", tls:false, base_dn:"", + object_class:"person", search_attr:"sAMAccountName", member_of:"", bind_name:"", @@ -415,6 +440,21 @@ export default { link_acl: [], auth : {}, }, + authLoginDialog : false, + authLoginLoading : false, + authLoginForm : { + name : "", + pwd : "", + }, + authLoginRules: { + name: [ + {required: true, message: '请输入账号', trigger: 'blur'}, + ], + pwd: [ + {required: true, message: '请输入密码', trigger: 'blur'}, + {min: 6, message: '长度至少 6 个字符', trigger: 'blur'} + ], + }, rules: { name: [ {required: true, message: '请输入组名', trigger: 'blur'}, @@ -437,7 +477,7 @@ export default { {required: true, message: '请输入服务器地址(含端口)', trigger: 'blur'} ], "auth.ldap.bind_name": [ - {required: true, message: '请输入管理员账号', trigger: 'blur'} + {required: true, message: '请输入管理员 DN', trigger: 'blur'} ], "auth.ldap.bind_pwd": [ {required: true, message: '请输入管理员密码', trigger: 'blur'} @@ -445,6 +485,9 @@ export default { "auth.ldap.base_dn": [ {required: true, message: '请输入Base DN值', trigger: 'blur'} ], + "auth.ldap.object_class": [ + {required: true, message: '请输入用户对象类', trigger: 'blur'} + ], "auth.ldap.search_attr": [ {required: true, message: '请输入用户唯一ID', trigger: 'blur'} ], @@ -549,6 +592,44 @@ export default { }); }); }, + testAuthLogin() { + this.$refs["authLoginForm"].validate((valid) => { + if (!valid) { + console.log('error submit!!'); + return false; + } + this.authLoginLoading = true; + axios.post('/group/auth_login', {name:this.authLoginForm.name, + pwd:this.authLoginForm.pwd, + auth:this.ruleForm.auth}).then(resp => { + const rdata = resp.data; + if (rdata.code === 0) { + this.$message.success("登录成功"); + } else { + this.$message.error(rdata.msg); + this.authLoginLoading = false; + } + console.log(rdata); + }).catch(error => { + this.$message.error('哦,请求出错'); + console.log(error); + this.authLoginLoading = false; + }); + }); + }, + openAuthLoginDialog() { + this.$refs["ruleForm"].validate((valid) => { + if (!valid) { + console.log('error submit!!'); + return false; + } + this.authLoginDialog = true; + // set authLoginFormName focus + this.$nextTick(() => { + this.$refs['authLoginFormName'].focus(); + }); + }); + }, resetForm(formName) { this.$refs[formName].resetFields(); }, From 262ad49df67cd0c5dabf52c2191b9d9af526ee6a Mon Sep 17 00:00:00 2001 From: lanrenwo Date: Fri, 13 Jan 2023 15:00:14 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E5=A2=9E=E5=8A=A0object=5Fclass=E7=9A=84?= =?UTF-8?q?=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/pages/group/List.vue | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/web/src/pages/group/List.vue b/web/src/pages/group/List.vue index e316e04..fcbbe21 100644 --- a/web/src/pages/group/List.vue +++ b/web/src/pages/group/List.vue @@ -500,6 +500,9 @@ export default { this.ruleForm.auth = JSON.parse(JSON.stringify(this.defAuth)); return ; } + if (row.auth.type == "ldap" && ! row.auth.ldap.object_class) { + row.auth.ldap.object_class = this.defAuth.ldap.object_class; + } this.ruleForm.auth = Object.assign(JSON.parse(JSON.stringify(this.defAuth)), row.auth); }, handleDel(row) { @@ -602,18 +605,18 @@ export default { axios.post('/group/auth_login', {name:this.authLoginForm.name, pwd:this.authLoginForm.pwd, auth:this.ruleForm.auth}).then(resp => { - const rdata = resp.data; - if (rdata.code === 0) { - this.$message.success("登录成功"); - } else { - this.$message.error(rdata.msg); - this.authLoginLoading = false; - } - console.log(rdata); - }).catch(error => { - this.$message.error('哦,请求出错'); - console.log(error); - this.authLoginLoading = false; + const rdata = resp.data; + if (rdata.code === 0) { + this.$message.success("登录成功"); + } else { + this.$message.error(rdata.msg); + } + this.authLoginLoading = false; + console.log(rdata); + }).catch(error => { + this.$message.error('哦,请求出错'); + console.log(error); + this.authLoginLoading = false; }); }); }, From 4d9919d43c8f5c1dee230134b77b0381e2a6c6f4 Mon Sep 17 00:00:00 2001 From: lanrenwo Date: Fri, 13 Jan 2023 18:02:13 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E7=9B=91=E6=8E=A7=E5=9B=BE=E8=A1=A8=E7=9A=84=E6=8A=A5=E9=94=99?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/pages/Home.vue | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web/src/pages/Home.vue b/web/src/pages/Home.vue index 9c071fe..02d0781 100644 --- a/web/src/pages/Home.vue +++ b/web/src/pages/Home.vue @@ -230,6 +230,9 @@ export default { case "mem": this.formatMem(data); break; } }).catch(error => { + if (error.response.status === 401) { + return ; + } this.$message.error('哦,请求出错'); console.log(error); }); From ef314c891b9383dddb2717ff72b111ad315edb60 Mon Sep 17 00:00:00 2001 From: lanrenwo Date: Tue, 17 Jan 2023 10:34:45 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E8=AE=A9=E6=B5=8B=E8=AF=95=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E7=99=BB=E5=BD=95=E6=A1=86=E5=9E=82=E7=9B=B4=E5=B1=85?= =?UTF-8?q?=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/pages/group/List.vue | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/web/src/pages/group/List.vue b/web/src/pages/group/List.vue index fcbbe21..69dab52 100644 --- a/web/src/pages/group/List.vue +++ b/web/src/pages/group/List.vue @@ -377,6 +377,7 @@ title="测试用户登录" :visible.sync="authLoginDialog" width="600px" + custom-class="valgin-dialog" center> @@ -389,6 +390,7 @@ 登录 取 消 + @@ -682,4 +684,20 @@ export default { .el-select { width: 80px; } + +::v-deep .valgin-dialog{ + display: flex; + flex-direction: column; + margin:0 !important; + position:absolute; + top:50%; + left:50%; + transform:translate(-50%,-50%); + max-height:calc(100% - 30px); + max-width:calc(100% - 30px); +} +::v-deep .valgin-dialog .el-dialog__body{ + flex:1; + overflow: auto; +}