mirror of https://github.com/bjdgyc/anylink.git
commit
8608c6acee
|
@ -118,3 +118,30 @@ func GroupDel(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
RespSucess(w, nil)
|
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")
|
||||||
|
}
|
||||||
|
|
|
@ -71,6 +71,7 @@ func StartAdmin() {
|
||||||
r.HandleFunc("/group/detail", GroupDetail)
|
r.HandleFunc("/group/detail", GroupDetail)
|
||||||
r.HandleFunc("/group/set", GroupSet)
|
r.HandleFunc("/group/set", GroupSet)
|
||||||
r.HandleFunc("/group/del", GroupDel)
|
r.HandleFunc("/group/del", GroupDel)
|
||||||
|
r.HandleFunc("/group/auth_login", GroupAuthLogin)
|
||||||
|
|
||||||
r.HandleFunc("/statsinfo/list", StatsInfoList)
|
r.HandleFunc("/statsinfo/list", StatsInfoList)
|
||||||
|
|
||||||
|
|
|
@ -225,6 +225,21 @@ func SetGroup(g *Group) error {
|
||||||
return err
|
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) {
|
func parseIpNet(s string) (string, *net.IPNet, error) {
|
||||||
ip, ipNet, err := net.ParseCIDR(s)
|
ip, ipNet, err := net.ParseCIDR(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -51,6 +51,7 @@ func TestGetGroupNames(t *testing.T) {
|
||||||
"bind_name": "userfind@abc.com",
|
"bind_name": "userfind@abc.com",
|
||||||
"bind_pwd": "afdbfdsafds",
|
"bind_pwd": "afdbfdsafds",
|
||||||
"base_dn": "dc=abc,dc=com",
|
"base_dn": "dc=abc,dc=com",
|
||||||
|
"object_class": "person",
|
||||||
"search_attr": "sAMAccountName",
|
"search_attr": "sAMAccountName",
|
||||||
"member_of": "cn=vpn,cn=user,dc=abc,dc=com",
|
"member_of": "cn=vpn,cn=user,dc=abc,dc=com",
|
||||||
},
|
},
|
||||||
|
|
|
@ -75,6 +75,7 @@ func TestCheckUser(t *testing.T) {
|
||||||
"bind_name": "userfind@abc.com",
|
"bind_name": "userfind@abc.com",
|
||||||
"bind_pwd": "afdbfdsafds",
|
"bind_pwd": "afdbfdsafds",
|
||||||
"base_dn": "dc=abc,dc=com",
|
"base_dn": "dc=abc,dc=com",
|
||||||
|
"object_class": "person",
|
||||||
"search_attr": "sAMAccountName",
|
"search_attr": "sAMAccountName",
|
||||||
"member_of": "cn=vpn,cn=user,dc=abc,dc=com",
|
"member_of": "cn=vpn,cn=user,dc=abc,dc=com",
|
||||||
},
|
},
|
||||||
|
|
|
@ -20,6 +20,7 @@ type AuthLdap struct {
|
||||||
BindName string `json:"bind_name"`
|
BindName string `json:"bind_name"`
|
||||||
BindPwd string `json:"bind_pwd"`
|
BindPwd string `json:"bind_pwd"`
|
||||||
BaseDn string `json:"base_dn"`
|
BaseDn string `json:"base_dn"`
|
||||||
|
ObjectClass string `json:"object_class"`
|
||||||
SearchAttr string `json:"search_attr"`
|
SearchAttr string `json:"search_attr"`
|
||||||
MemberOf string `json:"member_of"`
|
MemberOf string `json:"member_of"`
|
||||||
}
|
}
|
||||||
|
@ -40,7 +41,7 @@ func (auth AuthLdap) checkData(authData map[string]interface{}) error {
|
||||||
return errors.New("LDAP的服务器地址(含端口)填写有误")
|
return errors.New("LDAP的服务器地址(含端口)填写有误")
|
||||||
}
|
}
|
||||||
if auth.BindName == "" {
|
if auth.BindName == "" {
|
||||||
return errors.New("LDAP的管理员账号不能为空")
|
return errors.New("LDAP的管理员 DN不能为空")
|
||||||
}
|
}
|
||||||
if auth.BindPwd == "" {
|
if auth.BindPwd == "" {
|
||||||
return errors.New("LDAP的管理员密码不能为空")
|
return errors.New("LDAP的管理员密码不能为空")
|
||||||
|
@ -48,6 +49,9 @@ func (auth AuthLdap) checkData(authData map[string]interface{}) error {
|
||||||
if auth.BaseDn == "" || !ValidateDN(auth.BaseDn) {
|
if auth.BaseDn == "" || !ValidateDN(auth.BaseDn) {
|
||||||
return errors.New("LDAP的Base DN填写有误")
|
return errors.New("LDAP的Base DN填写有误")
|
||||||
}
|
}
|
||||||
|
if auth.ObjectClass == "" {
|
||||||
|
return errors.New("LDAP的用户对象类填写有误")
|
||||||
|
}
|
||||||
if auth.SearchAttr == "" {
|
if auth.SearchAttr == "" {
|
||||||
return errors.New("LDAP的用户唯一ID不能为空")
|
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)
|
err = l.Bind(auth.BindName, auth.BindPwd)
|
||||||
if err != nil {
|
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 + ")"
|
filterAttr += "(" + auth.SearchAttr + "=" + name + ")"
|
||||||
if auth.MemberOf != "" {
|
if auth.MemberOf != "" {
|
||||||
filterAttr += "(memberOf:=" + auth.MemberOf + ")"
|
filterAttr += "(memberOf:=" + auth.MemberOf + ")"
|
||||||
|
|
|
@ -230,6 +230,9 @@ export default {
|
||||||
case "mem": this.formatMem(data); break;
|
case "mem": this.formatMem(data); break;
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
if (error.response.status === 401) {
|
||||||
|
return ;
|
||||||
|
}
|
||||||
this.$message.error('哦,请求出错');
|
this.$message.error('哦,请求出错');
|
||||||
console.log(error);
|
console.log(error);
|
||||||
});
|
});
|
||||||
|
|
|
@ -251,7 +251,7 @@
|
||||||
<el-form-item label="开启TLS" prop="auth.ldap.tls">
|
<el-form-item label="开启TLS" prop="auth.ldap.tls">
|
||||||
<el-switch v-model="ruleForm.auth.ldap.tls"></el-switch>
|
<el-switch v-model="ruleForm.auth.ldap.tls"></el-switch>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="管理员账号" prop="auth.ldap.bind_name" :rules="this.ruleForm.auth.type== 'ldap' ? this.rules['auth.ldap.bind_name'] : [{ required: false }]">
|
<el-form-item label="管理员 DN" prop="auth.ldap.bind_name" :rules="this.ruleForm.auth.type== 'ldap' ? this.rules['auth.ldap.bind_name'] : [{ required: false }]">
|
||||||
<el-input v-model="ruleForm.auth.ldap.bind_name" placeholder="例如 CN=bindadmin,DC=abc,DC=COM"></el-input>
|
<el-input v-model="ruleForm.auth.ldap.bind_name" placeholder="例如 CN=bindadmin,DC=abc,DC=COM"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="管理员密码" prop="auth.ldap.bind_pwd" :rules="this.ruleForm.auth.type== 'ldap' ? this.rules['auth.ldap.bind_pwd'] : [{ required: false }]">
|
<el-form-item label="管理员密码" prop="auth.ldap.bind_pwd" :rules="this.ruleForm.auth.type== 'ldap' ? this.rules['auth.ldap.bind_pwd'] : [{ required: false }]">
|
||||||
|
@ -260,8 +260,11 @@
|
||||||
<el-form-item label="Base DN" prop="auth.ldap.base_dn" :rules="this.ruleForm.auth.type== 'ldap' ? this.rules['auth.ldap.base_dn'] : [{ required: false }]">
|
<el-form-item label="Base DN" prop="auth.ldap.base_dn" :rules="this.ruleForm.auth.type== 'ldap' ? this.rules['auth.ldap.base_dn'] : [{ required: false }]">
|
||||||
<el-input v-model="ruleForm.auth.ldap.base_dn" placeholder="例如 DC=abc,DC=com"></el-input>
|
<el-input v-model="ruleForm.auth.ldap.base_dn" placeholder="例如 DC=abc,DC=com"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="用户对象类" prop="auth.ldap.object_class" :rules="this.ruleForm.auth.type== 'ldap' ? this.rules['auth.ldap.object_class'] : [{ required: false }]">
|
||||||
|
<el-input v-model="ruleForm.auth.ldap.object_class" placeholder="例如 person / user / posixAccount"></el-input>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="用户唯一ID" prop="auth.ldap.search_attr" :rules="this.ruleForm.auth.type== 'ldap' ? this.rules['auth.ldap.search_attr'] : [{ required: false }]">
|
<el-form-item label="用户唯一ID" prop="auth.ldap.search_attr" :rules="this.ruleForm.auth.type== 'ldap' ? this.rules['auth.ldap.search_attr'] : [{ required: false }]">
|
||||||
<el-input v-model="ruleForm.auth.ldap.search_attr" placeholder="例如 sAMAccountName 或 uid"></el-input>
|
<el-input v-model="ruleForm.auth.ldap.search_attr" placeholder="例如 sAMAccountName / uid / cn"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="受限用户组" prop="auth.ldap.member_of">
|
<el-form-item label="受限用户组" prop="auth.ldap.member_of">
|
||||||
<el-input v-model="ruleForm.auth.ldap.member_of" placeholder="选填, 只允许指定组登入, 例如 CN=HomeWork,DC=abc,DC=com"></el-input>
|
<el-input v-model="ruleForm.auth.ldap.member_of" placeholder="选填, 只允许指定组登入, 例如 CN=HomeWork,DC=abc,DC=com"></el-input>
|
||||||
|
@ -359,13 +362,36 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
|
<templete v-if="activeTab == 'authtype' && ruleForm.auth.type != 'local'">
|
||||||
|
<el-button @click="openAuthLoginDialog()" style="margin-right:10px">测试登录</el-button>
|
||||||
|
</templete>
|
||||||
<el-button type="primary" @click="submitForm('ruleForm')">保存</el-button>
|
<el-button type="primary" @click="submitForm('ruleForm')">保存</el-button>
|
||||||
<el-button @click="closeDialog">取消</el-button>
|
<el-button @click="closeDialog">取消</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
<!--测试用户登录弹出框-->
|
||||||
|
<el-dialog
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
title="测试用户登录"
|
||||||
|
:visible.sync="authLoginDialog"
|
||||||
|
width="600px"
|
||||||
|
custom-class="valgin-dialog"
|
||||||
|
center>
|
||||||
|
<el-form :model="authLoginForm" :rules="authLoginRules" ref="authLoginForm" label-width="100px">
|
||||||
|
<el-form-item label="账号" prop="name">
|
||||||
|
<el-input v-model="authLoginForm.name" ref="authLoginFormName" @keydown.enter.native="testAuthLogin"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="密码" prop="pwd">
|
||||||
|
<el-input type="password" v-model="authLoginForm.pwd" @keydown.enter.native="testAuthLogin"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" @click="testAuthLogin()" :loading="authLoginLoading">登录</el-button>
|
||||||
|
<el-button @click="authLoginDialog = false">取 消</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -399,6 +425,7 @@ export default {
|
||||||
addr:"",
|
addr:"",
|
||||||
tls:false,
|
tls:false,
|
||||||
base_dn:"",
|
base_dn:"",
|
||||||
|
object_class:"person",
|
||||||
search_attr:"sAMAccountName",
|
search_attr:"sAMAccountName",
|
||||||
member_of:"",
|
member_of:"",
|
||||||
bind_name:"",
|
bind_name:"",
|
||||||
|
@ -415,6 +442,21 @@ export default {
|
||||||
link_acl: [],
|
link_acl: [],
|
||||||
auth : {},
|
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: {
|
rules: {
|
||||||
name: [
|
name: [
|
||||||
{required: true, message: '请输入组名', trigger: 'blur'},
|
{required: true, message: '请输入组名', trigger: 'blur'},
|
||||||
|
@ -437,7 +479,7 @@ export default {
|
||||||
{required: true, message: '请输入服务器地址(含端口)', trigger: 'blur'}
|
{required: true, message: '请输入服务器地址(含端口)', trigger: 'blur'}
|
||||||
],
|
],
|
||||||
"auth.ldap.bind_name": [
|
"auth.ldap.bind_name": [
|
||||||
{required: true, message: '请输入管理员账号', trigger: 'blur'}
|
{required: true, message: '请输入管理员 DN', trigger: 'blur'}
|
||||||
],
|
],
|
||||||
"auth.ldap.bind_pwd": [
|
"auth.ldap.bind_pwd": [
|
||||||
{required: true, message: '请输入管理员密码', trigger: 'blur'}
|
{required: true, message: '请输入管理员密码', trigger: 'blur'}
|
||||||
|
@ -445,6 +487,9 @@ export default {
|
||||||
"auth.ldap.base_dn": [
|
"auth.ldap.base_dn": [
|
||||||
{required: true, message: '请输入Base DN值', trigger: 'blur'}
|
{required: true, message: '请输入Base DN值', trigger: 'blur'}
|
||||||
],
|
],
|
||||||
|
"auth.ldap.object_class": [
|
||||||
|
{required: true, message: '请输入用户对象类', trigger: 'blur'}
|
||||||
|
],
|
||||||
"auth.ldap.search_attr": [
|
"auth.ldap.search_attr": [
|
||||||
{required: true, message: '请输入用户唯一ID', trigger: 'blur'}
|
{required: true, message: '请输入用户唯一ID', trigger: 'blur'}
|
||||||
],
|
],
|
||||||
|
@ -457,6 +502,9 @@ export default {
|
||||||
this.ruleForm.auth = JSON.parse(JSON.stringify(this.defAuth));
|
this.ruleForm.auth = JSON.parse(JSON.stringify(this.defAuth));
|
||||||
return ;
|
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);
|
this.ruleForm.auth = Object.assign(JSON.parse(JSON.stringify(this.defAuth)), row.auth);
|
||||||
},
|
},
|
||||||
handleDel(row) {
|
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) {
|
resetForm(formName) {
|
||||||
this.$refs[formName].resetFields();
|
this.$refs[formName].resetFields();
|
||||||
},
|
},
|
||||||
|
@ -598,4 +684,20 @@ export default {
|
||||||
.el-select {
|
.el-select {
|
||||||
width: 80px;
|
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;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue