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/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); }); diff --git a/web/src/pages/group/List.vue b/web/src/pages/group/List.vue index 1b4b816..69dab52 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,36 @@ - 保存 - 取消 + + 测试登录 + + 保存 + 取消 - + + + + + + + + + + + 登录 + 取 消 + + + @@ -399,6 +425,7 @@ export default { addr:"", tls:false, base_dn:"", + object_class:"person", search_attr:"sAMAccountName", member_of:"", bind_name:"", @@ -415,6 +442,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 +479,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 +487,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'} ], @@ -457,6 +502,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) { @@ -549,6 +597,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(); }, @@ -598,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; +}