mirror of
https://github.com/bjdgyc/anylink.git
synced 2025-08-08 10:02:09 +08:00
新增radius认证方式
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package dbdata
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
@@ -32,19 +33,27 @@ type ValData struct {
|
||||
Note string `json:"note"`
|
||||
}
|
||||
|
||||
type AuthRadius struct {
|
||||
Addr string `json:"addr"`
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
|
||||
// type Group struct {
|
||||
// Id int `json:"id" xorm:"pk autoincr not null"`
|
||||
// Name string `json:"name" xorm:"not null unique"`
|
||||
// Note string `json:"note"`
|
||||
// AllowLan bool `json:"allow_lan"`
|
||||
// ClientDns []ValData `json:"client_dns"`
|
||||
// RouteInclude []ValData `json:"route_include"`
|
||||
// RouteExclude []ValData `json:"route_exclude"`
|
||||
// LinkAcl []GroupLinkAcl `json:"link_acl"`
|
||||
// Bandwidth int `json:"bandwidth"` // 带宽限制
|
||||
// Status int8 `json:"status"` // 1正常
|
||||
// CreatedAt time.Time `json:"created_at"`
|
||||
// UpdatedAt time.Time `json:"updated_at"`
|
||||
// Id int `json:"id" xorm:"pk autoincr not null"`
|
||||
// Name string `json:"name" xorm:"varchar(60) not null unique"`
|
||||
// Note string `json:"note" xorm:"varchar(255)"`
|
||||
// AllowLan bool `json:"allow_lan" xorm:"Bool"`
|
||||
// ClientDns []ValData `json:"client_dns" xorm:"Text"`
|
||||
// RouteInclude []ValData `json:"route_include" xorm:"Text"`
|
||||
// RouteExclude []ValData `json:"route_exclude" xorm:"Text"`
|
||||
// DsExcludeDomains string `json:"ds_exclude_domains" xorm:"Text"`
|
||||
// DsIncludeDomains string `json:"ds_include_domains" xorm:"Text"`
|
||||
// LinkAcl []GroupLinkAcl `json:"link_acl" xorm:"Text"`
|
||||
// Bandwidth int `json:"bandwidth" xorm:"Int"` // 带宽限制
|
||||
// Auth map[string]interface{} `json:"auth" xorm:"not null default '{}' varchar(255)"` // 认证方式
|
||||
// Status int8 `json:"status" xorm:"Int"` // 1正常
|
||||
// CreatedAt time.Time `json:"created_at" xorm:"DateTime created"`
|
||||
// UpdatedAt time.Time `json:"updated_at" xorm:"DateTime updated"`
|
||||
// }
|
||||
|
||||
func GetGroupNames() []string {
|
||||
@@ -145,6 +154,20 @@ func SetGroup(g *Group) error {
|
||||
if err != nil {
|
||||
return errors.New("排除域名有误:" + err.Error())
|
||||
}
|
||||
// 处理认证类型
|
||||
switch g.Auth["type"] {
|
||||
case "local":
|
||||
g.Auth = map[string]interface{}{
|
||||
"type": g.Auth["type"],
|
||||
}
|
||||
case "radius":
|
||||
err = checkRadiusData(g.Auth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return errors.New("未知的认证类型")
|
||||
}
|
||||
|
||||
g.UpdatedAt = time.Now()
|
||||
if g.Id > 0 {
|
||||
@@ -167,6 +190,24 @@ func parseIpNet(s string) (string, *net.IPNet, error) {
|
||||
|
||||
return ipMask, ipNet, nil
|
||||
}
|
||||
|
||||
func checkRadiusData(auth map[string]interface{}) error {
|
||||
radisConf := AuthRadius{}
|
||||
bodyBytes, err := json.Marshal(auth["radius"])
|
||||
if err != nil {
|
||||
return errors.New("Radius的密钥/服务器地址填写有误")
|
||||
}
|
||||
json.Unmarshal(bodyBytes, &radisConf)
|
||||
if !ValidateIpPort(radisConf.Addr) {
|
||||
return errors.New("Radius的服务器地址填写有误")
|
||||
}
|
||||
// freeradius官网最大8000字符, 这里限制800
|
||||
if len(radisConf.Secret) < 8 || len(radisConf.Secret) > 800 {
|
||||
return errors.New("Radius的密钥长度需在8~800个字符之间")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func CheckDomainNames(domains string) error {
|
||||
if domains == "" {
|
||||
return nil
|
||||
@@ -187,3 +228,8 @@ func ValidateDomainName(domain string) bool {
|
||||
RegExp := regexp.MustCompile(`^([a-zA-Z0-9][-a-zA-Z0-9]{0,62}\.)+[A-Za-z]{2,18}$`)
|
||||
return RegExp.MatchString(domain)
|
||||
}
|
||||
|
||||
func ValidateIpPort(addr string) bool {
|
||||
RegExp := regexp.MustCompile(`^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\:([0-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-5]{2}[0-3][0-5])$$`)
|
||||
return RegExp.MatchString(addr)
|
||||
}
|
||||
|
@@ -6,20 +6,21 @@ import (
|
||||
)
|
||||
|
||||
type Group struct {
|
||||
Id int `json:"id" xorm:"pk autoincr not null"`
|
||||
Name string `json:"name" xorm:"varchar(60) not null unique"`
|
||||
Note string `json:"note" xorm:"varchar(255)"`
|
||||
AllowLan bool `json:"allow_lan" xorm:"Bool"`
|
||||
ClientDns []ValData `json:"client_dns" xorm:"Text"`
|
||||
RouteInclude []ValData `json:"route_include" xorm:"Text"`
|
||||
RouteExclude []ValData `json:"route_exclude" xorm:"Text"`
|
||||
DsExcludeDomains string `json:"ds_exclude_domains" xorm:"Text"`
|
||||
DsIncludeDomains string `json:"ds_include_domains" xorm:"Text"`
|
||||
LinkAcl []GroupLinkAcl `json:"link_acl" xorm:"Text"`
|
||||
Bandwidth int `json:"bandwidth" xorm:"Int"` // 带宽限制
|
||||
Status int8 `json:"status" xorm:"Int"` // 1正常
|
||||
CreatedAt time.Time `json:"created_at" xorm:"DateTime created"`
|
||||
UpdatedAt time.Time `json:"updated_at" xorm:"DateTime updated"`
|
||||
Id int `json:"id" xorm:"pk autoincr not null"`
|
||||
Name string `json:"name" xorm:"varchar(60) not null unique"`
|
||||
Note string `json:"note" xorm:"varchar(255)"`
|
||||
AllowLan bool `json:"allow_lan" xorm:"Bool"`
|
||||
ClientDns []ValData `json:"client_dns" xorm:"Text"`
|
||||
RouteInclude []ValData `json:"route_include" xorm:"Text"`
|
||||
RouteExclude []ValData `json:"route_exclude" xorm:"Text"`
|
||||
DsExcludeDomains string `json:"ds_exclude_domains" xorm:"Text"`
|
||||
DsIncludeDomains string `json:"ds_include_domains" xorm:"Text"`
|
||||
LinkAcl []GroupLinkAcl `json:"link_acl" xorm:"Text"`
|
||||
Bandwidth int `json:"bandwidth" xorm:"Int"` // 带宽限制
|
||||
Auth map[string]interface{} `json:"auth" xorm:"not null default '{}' varchar(255)"` // 认证方式
|
||||
Status int8 `json:"status" xorm:"Int"` // 1正常
|
||||
CreatedAt time.Time `json:"created_at" xorm:"DateTime created"`
|
||||
UpdatedAt time.Time `json:"updated_at" xorm:"DateTime updated"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
|
@@ -1,13 +1,18 @@
|
||||
package dbdata
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/bjdgyc/anylink/base"
|
||||
"github.com/bjdgyc/anylink/pkg/utils"
|
||||
"github.com/xlzd/gotp"
|
||||
"layeh.com/radius"
|
||||
"layeh.com/radius/rfc2865"
|
||||
)
|
||||
|
||||
// type User struct {
|
||||
@@ -68,6 +73,38 @@ func SetUser(v *User) error {
|
||||
|
||||
// 验证用户登陆信息
|
||||
func CheckUser(name, pwd, group string) error {
|
||||
// 获取登入的group数据
|
||||
groupData := &Group{}
|
||||
err := One("Name", group, groupData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s %s", name, "No用户组")
|
||||
}
|
||||
if len(groupData.Auth) == 0 {
|
||||
groupData.Auth["type"] = "local"
|
||||
}
|
||||
base.Debug(name + " auth type: " + fmt.Sprintf("%s", groupData.Auth["type"]))
|
||||
switch groupData.Auth["type"] {
|
||||
case "local":
|
||||
return checkLocalUser(name, pwd, group)
|
||||
case "radius":
|
||||
radisConf := AuthRadius{}
|
||||
bodyBytes, err := json.Marshal(groupData.Auth["radius"])
|
||||
if err != nil {
|
||||
fmt.Errorf("%s %s", name, "Radius出现Marshal错误")
|
||||
}
|
||||
err = json.Unmarshal(bodyBytes, &radisConf)
|
||||
if err != nil {
|
||||
fmt.Errorf("%s %s", name, "Radius出现Unmarshal错误")
|
||||
}
|
||||
return checkRadiusUser(name, pwd, radisConf)
|
||||
default:
|
||||
return fmt.Errorf("%s %s", name, "无效的认证类型")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 验证本地用户登陆信息
|
||||
func checkLocalUser(name, pwd, group string) error {
|
||||
// TODO 严重问题
|
||||
// return nil
|
||||
|
||||
@@ -108,6 +145,22 @@ func CheckUser(name, pwd, group string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkRadiusUser(name string, pwd string, raduisConf AuthRadius) error {
|
||||
packet := radius.New(radius.CodeAccessRequest, []byte(raduisConf.Secret))
|
||||
rfc2865.UserName_SetString(packet, name)
|
||||
rfc2865.UserPassword_SetString(packet, pwd)
|
||||
ctx, done := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer done()
|
||||
response, err := radius.Exchange(ctx, packet, raduisConf.Addr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s %s", name, "Radius服务器连接异常, 请检测服务器和端口")
|
||||
}
|
||||
if response.Code != radius.CodeAccessAccept {
|
||||
return fmt.Errorf("%s %s", name, "Radius:用户名或密码错误")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
userOtpMux = sync.Mutex{}
|
||||
userOtp = map[string]time.Time{}
|
||||
|
Reference in New Issue
Block a user