diff --git a/Dockerfile b/Dockerfile
index d1b58eb..cec779e 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -18,7 +18,7 @@ COPY --from=builder_node /web/ui  /anylink/server/ui
 #TODO 本地打包时使用镜像
 RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories
 RUN apk add --no-cache git gcc musl-dev
-RUN cd /anylink/server;go build -o anylink -ldflags "-X main.CommitId=$(git rev-parse HEAD)" \
+RUN cd /anylink/server;go mod tidy;go build -o anylink -ldflags "-X main.CommitId=$(git rev-parse HEAD)" \
     && /anylink/server/anylink tool -v
 
 # anylink
diff --git a/README.md b/README.md
index f269afa..2622f03 100644
--- a/README.md
+++ b/README.md
@@ -30,6 +30,16 @@ AnyLink 服务端仅在 CentOS 7、Ubuntu 18.04 测试通过,如需要安装
 
 ![online](doc/screenshot/online.jpg)
 
+## Donate
+
+> 如果您觉得 anylink 对你有帮助,欢迎给我们打赏,也是帮助 anylink 更好的发展。
+>
+> [查看打赏列表](doc/README.md)
+
+<p>
+    <img src="doc/screenshot/wxpay2.png" width="400" />
+</p>
+
 ## Installation
 
 > 没有编程基础的同学建议直接下载 release 包,从下面的地址下载 anylink-deploy.tar.gz
@@ -78,12 +88,15 @@ sudo ./anylink
 - [x] 支持 [proxy protocol v1](http://www.haproxy.org/download/2.2/doc/proxy-protocol.txt) 协议
 - [x] 用户组支持
 - [x] 多用户支持
+- [x] 用户策略支持
 - [x] TOTP 令牌支持
 - [x] TOTP 令牌开关
 - [x] 流量速率限制
 - [x] 后台管理界面
 - [x] 访问权限管理
 - [x] IP 访问审计功能
+- [x] 域名动态拆分隧道(域名路由功能)
+- [x] radius认证支持
 - [ ] 基于 ipvtap 设备的桥接访问模式
 
 ## Config
@@ -268,15 +281,6 @@ sh bridge-init.sh
    docker build -t anylink .
    ```
 
-## Donate
-
-> 如果您觉得 anylink 对你有帮助,欢迎给我们打赏,也是帮助 anylink 更好的发展。
->
-> [查看打赏列表](doc/README.md)
-
-<p>
-    <img src="doc/screenshot/wxpay2.png" width="400" />
-</p>
 
 ## 常见问题
 
diff --git a/build.sh b/build.sh
index 2b57fd5..76acaf5 100644
--- a/build.sh
+++ b/build.sh
@@ -31,6 +31,7 @@ rm -rf ui
 cp -rf $cpath/web/ui .
 #国内可替换源加快速度
 export GOPROXY=https://goproxy.io
+go mod tidy
 go build -v -o anylink -ldflags "-X main.CommitId=$(git rev-parse HEAD)"
 RETVAL $?
 
diff --git a/doc/README.md b/doc/README.md
index 64d5e58..6366342 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -10,11 +10,17 @@
 
 > 感谢以下同学的打赏,AnyLink 有你更美好!
 
-| 昵称     | 主页                         |
-| -------- | ---------------------------- |
-| 代码oo8 |                              |
-| 甘磊     | https://github.com/ganlei333 |
-| Oo@     | https://github.com/chooop    |
-| 虚极静笃 |                              |
-| Ficapy |                              |
+| 昵称 | 主页                         |
+| -- | ---------------------------- |
+| 代码oo8 |                           |
+| 甘磊 | https://github.com/ganlei333 |
+| Oo@ | https://github.com/chooop    |
+| 虚极静笃 |                           |
+| 请喝可乐 |                           |
+| 加油加油 |                           |
+| 李建 |                              |
+| lanbin |                            |
+| 乐在东途 |                           |
+
+
 
diff --git a/server/admin/api_group.go b/server/admin/api_group.go
index 17fbdb7..dd440e1 100644
--- a/server/admin/api_group.go
+++ b/server/admin/api_group.go
@@ -62,7 +62,9 @@ func GroupDetail(w http.ResponseWriter, r *http.Request) {
 		RespError(w, RespInternalErr, err)
 		return
 	}
-
+	if len(data.Auth) == 0 {
+		data.Auth["type"] = "local"
+	}
 	RespSucess(w, data)
 }
 
diff --git a/server/admin/api_policy.go b/server/admin/api_policy.go
new file mode 100644
index 0000000..a4934c9
--- /dev/null
+++ b/server/admin/api_policy.go
@@ -0,0 +1,98 @@
+package admin
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"net/http"
+	"strconv"
+
+	"github.com/bjdgyc/anylink/dbdata"
+)
+
+func PolicyList(w http.ResponseWriter, r *http.Request) {
+	_ = r.ParseForm()
+	pageS := r.FormValue("page")
+	page, _ := strconv.Atoi(pageS)
+	if page < 1 {
+		page = 1
+	}
+
+	var pageSize = dbdata.PageSize
+
+	count := dbdata.CountAll(&dbdata.Policy{})
+
+	var datas []dbdata.Policy
+	err := dbdata.Find(&datas, pageSize, page)
+	if err != nil {
+		RespError(w, RespInternalErr, err)
+		return
+	}
+
+	data := map[string]interface{}{
+		"count":     count,
+		"page_size": pageSize,
+		"datas":     datas,
+	}
+
+	RespSucess(w, data)
+}
+
+func PolicyDetail(w http.ResponseWriter, r *http.Request) {
+	_ = r.ParseForm()
+	idS := r.FormValue("id")
+	id, _ := strconv.Atoi(idS)
+	if id < 1 {
+		RespError(w, RespParamErr, "Id错误")
+		return
+	}
+
+	var data dbdata.Policy
+	err := dbdata.One("Id", id, &data)
+	if err != nil {
+		RespError(w, RespInternalErr, err)
+		return
+	}
+
+	RespSucess(w, data)
+}
+
+func PolicySet(w http.ResponseWriter, r *http.Request) {
+	body, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		RespError(w, RespInternalErr, err)
+		return
+	}
+	defer r.Body.Close()
+	v := &dbdata.Policy{}
+	err = json.Unmarshal(body, v)
+	if err != nil {
+		RespError(w, RespInternalErr, err)
+		return
+	}
+
+	err = dbdata.SetPolicy(v)
+	if err != nil {
+		RespError(w, RespInternalErr, err)
+		return
+	}
+
+	RespSucess(w, nil)
+}
+
+func PolicyDel(w http.ResponseWriter, r *http.Request) {
+	_ = r.ParseForm()
+	idS := r.FormValue("id")
+	id, _ := strconv.Atoi(idS)
+	if id < 1 {
+		RespError(w, RespParamErr, "Id错误")
+		return
+	}
+
+	data := dbdata.Policy{Id: id}
+	err := dbdata.Del(&data)
+	if err != nil {
+		RespError(w, RespInternalErr, err)
+		return
+	}
+	RespSucess(w, nil)
+}
diff --git a/server/admin/server.go b/server/admin/server.go
index 98f3b20..75b6ac9 100644
--- a/server/admin/server.go
+++ b/server/admin/server.go
@@ -52,6 +52,10 @@ func StartAdmin() {
 	r.HandleFunc("/user/ip_map/detail", UserIpMapDetail)
 	r.HandleFunc("/user/ip_map/set", UserIpMapSet)
 	r.HandleFunc("/user/ip_map/del", UserIpMapDel)
+	r.HandleFunc("/user/policy/list", PolicyList)
+	r.HandleFunc("/user/policy/detail", PolicyDetail)
+	r.HandleFunc("/user/policy/set", PolicySet)
+	r.HandleFunc("/user/policy/del", PolicyDel)
 
 	r.HandleFunc("/group/list", GroupList)
 	r.HandleFunc("/group/names", GroupNames)
diff --git a/server/base/cfg.go b/server/base/cfg.go
index 49a9c92..5690f08 100644
--- a/server/base/cfg.go
+++ b/server/base/cfg.go
@@ -66,6 +66,7 @@ type ServerConfig struct {
 	CstpDpd         int    `json:"cstp_dpd"`       // Dead peer detection in seconds
 	MobileKeepalive int    `json:"mobile_keepalive"`
 	MobileDpd       int    `json:"mobile_dpd"`
+	Mtu             int    `json:"mtu"`
 
 	SessionTimeout int `json:"session_timeout"` // in seconds
 	// AuthTimeout    int `json:"auth_timeout"`    // in seconds
diff --git a/server/base/config.go b/server/base/config.go
index b7edc7b..bdb6dc1 100644
--- a/server/base/config.go
+++ b/server/base/config.go
@@ -54,6 +54,7 @@ var configs = []config{
 	{Typ: cfgInt, Name: "cstp_dpd", Usage: "死链接检测时间(秒)", ValInt: 30},
 	{Typ: cfgInt, Name: "mobile_keepalive", Usage: "移动端keepalive接检测时间(秒)", ValInt: 50},
 	{Typ: cfgInt, Name: "mobile_dpd", Usage: "移动端死链接检测时间(秒)", ValInt: 60},
+	{Typ: cfgInt, Name: "mtu", Usage: "最大传输单元MTU", ValInt: 1460},
 	{Typ: cfgInt, Name: "session_timeout", Usage: "session过期时间(秒)", ValInt: 3600},
 	// {Typ: cfgInt, Name: "auth_timeout", Usage: "auth_timeout", ValInt: 0},
 	{Typ: cfgInt, Name: "audit_interval", Usage: "审计去重间隔(秒),-1关闭", ValInt: -1},
diff --git a/server/conf/server-sample.toml b/server/conf/server-sample.toml
index 402e03f..13a8835 100644
--- a/server/conf/server-sample.toml
+++ b/server/conf/server-sample.toml
@@ -60,6 +60,10 @@ cstp_keepalive = 20
 cstp_dpd = 30
 mobile_keepalive = 40
 mobile_dpd = 50
+
+#设置最大传输单元
+mtu = 1460
+
 #session过期时间,用于断线重连,0永不过期
 session_timeout = 3600
 auth_timeout = 0
diff --git a/server/dbdata/db.go b/server/dbdata/db.go
index b6f9263..994651b 100644
--- a/server/dbdata/db.go
+++ b/server/dbdata/db.go
@@ -25,7 +25,7 @@ func initDb() {
 	}
 
 	// 初始化数据库
-	err = xdb.Sync2(&User{}, &Setting{}, &Group{}, &IpMap{}, &AccessAudit{})
+	err = xdb.Sync2(&User{}, &Setting{}, &Group{}, &IpMap{}, &AccessAudit{}, &Policy{})
 	if err != nil {
 		base.Fatal(err)
 	}
diff --git a/server/dbdata/group.go b/server/dbdata/group.go
index 252f3f8..112805d 100644
--- a/server/dbdata/group.go
+++ b/server/dbdata/group.go
@@ -4,6 +4,8 @@ import (
 	"errors"
 	"fmt"
 	"net"
+	"regexp"
+	"strings"
 	"time"
 
 	"github.com/bjdgyc/anylink/base"
@@ -31,18 +33,21 @@ type ValData struct {
 }
 
 // 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 {
@@ -127,6 +132,43 @@ func SetGroup(g *Group) error {
 		}
 	}
 	g.ClientDns = clientDns
+	// 域名拆分隧道,不能同时填写
+	g.DsIncludeDomains = strings.TrimSpace(g.DsIncludeDomains)
+	g.DsExcludeDomains = strings.TrimSpace(g.DsExcludeDomains)
+	if g.DsIncludeDomains != "" && g.DsExcludeDomains != "" {
+		return errors.New("包含/排除域名不能同时填写")
+	}
+	// 校验包含域名的格式
+	err = CheckDomainNames(g.DsIncludeDomains)
+	if err != nil {
+		return errors.New("包含域名有误:" + err.Error())
+	}
+	// 校验排除域名的格式
+	err = CheckDomainNames(g.DsExcludeDomains)
+	if err != nil {
+		return errors.New("排除域名有误:" + err.Error())
+	}
+	// 处理登入方式的逻辑
+	defAuth := map[string]interface{}{
+		"type": "local",
+	}
+	if len(g.Auth) == 0 {
+		g.Auth = defAuth
+	}
+	authType := g.Auth["type"].(string)
+	if authType == "local" {
+		g.Auth = defAuth
+	} else {
+		_, ok := authRegistry[authType]
+		if !ok {
+			return errors.New("未知的认证方式: " + authType)
+		}
+		auth := makeInstance(authType).(IUserAuth)
+		err = auth.checkData(g.Auth)
+		if err != nil {
+			return err
+		}
+	}
 
 	g.UpdatedAt = time.Now()
 	if g.Id > 0 {
@@ -149,3 +191,24 @@ func parseIpNet(s string) (string, *net.IPNet, error) {
 
 	return ipMask, ipNet, nil
 }
+
+func CheckDomainNames(domains string) error {
+	if domains == "" {
+		return nil
+	}
+	str_slice := strings.Split(domains, ",")
+	for _, val := range str_slice {
+		if val == "" {
+			return errors.New(val + " 请以逗号分隔域名")
+		}
+		if !ValidateDomainName(val) {
+			return errors.New(val + " 域名有误")
+		}
+	}
+	return nil
+}
+
+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)
+}
diff --git a/server/dbdata/group_test.go b/server/dbdata/group_test.go
index ee1dee1..7d27c7f 100644
--- a/server/dbdata/group_test.go
+++ b/server/dbdata/group_test.go
@@ -24,8 +24,25 @@ func TestGetGroupNames(t *testing.T) {
 	err = SetGroup(&g3)
 	ast.Nil(err)
 
+	authData := map[string]interface{}{
+		"type": "radius",
+		"radius": map[string]string{
+			"addr":   "192.168.8.12:1044",
+			"secret": "43214132",
+		},
+	}
+	g4 := Group{Name: "g4", ClientDns: []ValData{{Val: "114.114.114.114"}}, Auth: authData}
+	err = SetGroup(&g4)
+	ast.Nil(err)
+	g5 := Group{Name: "g5", ClientDns: []ValData{{Val: "114.114.114.114"}}, DsIncludeDomains: "baidu.com,163.com"}
+	err = SetGroup(&g5)
+	ast.Nil(err)
+	g6 := Group{Name: "g6", ClientDns: []ValData{{Val: "114.114.114.114"}}, DsExcludeDomains: "com.cn,qq.com"}
+	err = SetGroup(&g6)
+	ast.Nil(err)
+
 	// 判断所有数据
-	gAll := []string{"g1", "g2", "g3"}
+	gAll := []string{"g1", "g2", "g3", "g4", "g5", "g6"}
 	gs := GetGroupNames()
 	for _, v := range gs {
 		ast.Equal(true, utils.InArrStr(gAll, v))
diff --git a/server/dbdata/policy.go b/server/dbdata/policy.go
new file mode 100644
index 0000000..9777804
--- /dev/null
+++ b/server/dbdata/policy.go
@@ -0,0 +1,101 @@
+package dbdata
+
+import (
+	"errors"
+	"net"
+	"strings"
+	"time"
+)
+
+func GetPolicy(Username string) *Policy {
+	policyData := &Policy{}
+	err := One("Username", Username, policyData)
+	if err != nil {
+		return policyData
+	}
+	return policyData
+}
+
+func SetPolicy(p *Policy) error {
+	var err error
+	if p.Username == "" {
+		return errors.New("用户名错误")
+	}
+
+	// 包含路由
+	routeInclude := []ValData{}
+	for _, v := range p.RouteInclude {
+		if v.Val != "" {
+			if v.Val == All {
+				routeInclude = append(routeInclude, v)
+				continue
+			}
+
+			ipMask, _, err := parseIpNet(v.Val)
+			if err != nil {
+				return errors.New("RouteInclude 错误" + err.Error())
+			}
+
+			v.IpMask = ipMask
+			routeInclude = append(routeInclude, v)
+		}
+	}
+	p.RouteInclude = routeInclude
+	// 排除路由
+	routeExclude := []ValData{}
+	for _, v := range p.RouteExclude {
+		if v.Val != "" {
+			ipMask, _, err := parseIpNet(v.Val)
+			if err != nil {
+				return errors.New("RouteExclude 错误" + err.Error())
+			}
+			v.IpMask = ipMask
+			routeExclude = append(routeExclude, v)
+		}
+	}
+	p.RouteExclude = routeExclude
+
+	// DNS 判断
+	clientDns := []ValData{}
+	for _, v := range p.ClientDns {
+		if v.Val != "" {
+			ip := net.ParseIP(v.Val)
+			if ip.String() != v.Val {
+				return errors.New("DNS IP 错误")
+			}
+			clientDns = append(clientDns, v)
+		}
+	}
+	if len(routeInclude) == 0 || (len(routeInclude) == 1 && routeInclude[0].Val == "all") {
+		if len(clientDns) == 0 {
+			return errors.New("默认路由,必须设置一个DNS")
+		}
+	}
+	p.ClientDns = clientDns
+
+	// 域名拆分隧道,不能同时填写
+	p.DsIncludeDomains = strings.TrimSpace(p.DsIncludeDomains)
+	p.DsExcludeDomains = strings.TrimSpace(p.DsExcludeDomains)
+	if p.DsIncludeDomains != "" && p.DsExcludeDomains != "" {
+		return errors.New("包含/排除域名不能同时填写")
+	}
+	// 校验包含域名的格式
+	err = CheckDomainNames(p.DsIncludeDomains)
+	if err != nil {
+		return errors.New("包含域名有误:" + err.Error())
+	}
+	// 校验排除域名的格式
+	err = CheckDomainNames(p.DsExcludeDomains)
+	if err != nil {
+		return errors.New("排除域名有误:" + err.Error())
+	}
+
+	p.UpdatedAt = time.Now()
+	if p.Id > 0 {
+		err = Set(p)
+	} else {
+		err = Add(p)
+	}
+
+	return err
+}
diff --git a/server/dbdata/policy_test.go b/server/dbdata/policy_test.go
new file mode 100644
index 0000000..e2dd409
--- /dev/null
+++ b/server/dbdata/policy_test.go
@@ -0,0 +1,45 @@
+package dbdata
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestGetPolicy(t *testing.T) {
+	ast := assert.New(t)
+
+	preIpData()
+	defer closeIpdata()
+
+	// 添加 Policy
+	p1 := Policy{Username: "a1", ClientDns: []ValData{{Val: "114.114.114.114"}}, DsExcludeDomains: "baidu.com,163.com"}
+	err := SetPolicy(&p1)
+	ast.Nil(err)
+
+	p2 := Policy{Username: "a2", ClientDns: []ValData{{Val: "114.114.114.114"}}, DsExcludeDomains: "com.cn,qq.com"}
+	err = SetPolicy(&p2)
+	ast.Nil(err)
+
+	route := []ValData{{Val: "192.168.1.1/24"}}
+	p3 := Policy{Username: "a3", ClientDns: []ValData{{Val: "114.114.114.114"}}, RouteInclude: route, DsExcludeDomains: "com.cn,qq.com"}
+	err = SetPolicy(&p3)
+	ast.Nil(err)
+	// 判断 IpMask
+	ast.Equal(p3.RouteInclude[0].IpMask, "192.168.1.1/255.255.255.0")
+
+	route2 := []ValData{{Val: "192.168.2.1/24"}}
+	p4 := Policy{Username: "a4", ClientDns: []ValData{{Val: "114.114.114.114"}}, RouteExclude: route2, DsIncludeDomains: "com.cn,qq.com"}
+	err = SetPolicy(&p4)
+	ast.Nil(err)
+	// 判断 IpMask
+	ast.Equal(p4.RouteExclude[0].IpMask, "192.168.2.1/255.255.255.0")
+
+	// 判断所有数据
+	var userPolicy *Policy
+	pAll := []string{"a1", "a2", "a3", "a4"}
+	for _, v := range pAll {
+		userPolicy = GetPolicy(v)
+		ast.NotEqual(userPolicy.Id, 0, "user policy id is zero")
+	}
+}
diff --git a/server/dbdata/tables.go b/server/dbdata/tables.go
index 48df52e..56b2dbe 100644
--- a/server/dbdata/tables.go
+++ b/server/dbdata/tables.go
@@ -6,18 +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"`
-	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 {
@@ -65,3 +68,17 @@ type AccessAudit struct {
 	DstPort   uint16    `json:"dst_port" xorm:"not null"`
 	CreatedAt time.Time `json:"created_at" xorm:"DateTime"`
 }
+
+type Policy struct {
+	Id               int       `json:"id" xorm:"pk autoincr not null"`
+	Username         string    `json:"username" xorm:"varchar(60) not null unique"`
+	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"`
+	Status           int8      `json:"status" xorm:"Int"` // 1正常 0 禁用
+	CreatedAt        time.Time `json:"created_at" xorm:"DateTime created"`
+	UpdatedAt        time.Time `json:"updated_at" xorm:"DateTime updated"`
+}
diff --git a/server/dbdata/user.go b/server/dbdata/user.go
index 5fbb2d7..7834013 100644
--- a/server/dbdata/user.go
+++ b/server/dbdata/user.go
@@ -66,8 +66,34 @@ func SetUser(v *User) error {
 	return err
 }
 
-// 验证用户登陆信息
+// 验证用户登录信息
 func CheckUser(name, pwd, group string) error {
+	// 获取登入的group数据
+	groupData := &Group{}
+	err := One("Name", group, groupData)
+	if err != nil || groupData.Status != 1 {
+		return fmt.Errorf("%s - %s", name, "用户组错误")
+	}
+	// 初始化Auth
+	if len(groupData.Auth) == 0 {
+		groupData.Auth["type"] = "local"
+	}
+	authType := groupData.Auth["type"].(string)
+	// 本地认证方式
+	if authType == "local" {
+		return checkLocalUser(name, pwd, group)
+	}
+	// 其它认证方式, 支持自定义
+	_, ok := authRegistry[authType]
+	if !ok {
+		return fmt.Errorf("%s %s", "未知的认证方式: ", authType)
+	}
+	auth := makeInstance(authType).(IUserAuth)
+	return auth.checkUser(name, pwd, groupData)
+}
+
+// 验证本地用户登录信息
+func checkLocalUser(name, pwd, group string) error {
 	// TODO 严重问题
 	// return nil
 
@@ -84,12 +110,6 @@ func CheckUser(name, pwd, group string) error {
 	if !utils.InArrStr(v.Groups, group) {
 		return fmt.Errorf("%s %s", name, "用户组错误")
 	}
-	groupData := &Group{}
-	err = One("Name", group, groupData)
-	if err != nil || groupData.Status != 1 {
-		return fmt.Errorf("%s - %s", name, "用户组错误")
-	}
-
 	// 判断otp信息
 	pinCode := pwd
 	if !v.DisableOtp {
diff --git a/server/dbdata/user_test.go b/server/dbdata/user_test.go
index e076672..8e46dcc 100644
--- a/server/dbdata/user_test.go
+++ b/server/dbdata/user_test.go
@@ -40,4 +40,30 @@ func TestCheckUser(t *testing.T) {
 	_ = SetUser(&u)
 	err = CheckUser("aaa", u.PinCode, group)
 	ast.Nil(err)
+
+	// 添加一个radius组
+	group2 := "group2"
+	authData := map[string]interface{}{
+		"type": "radius",
+		"radius": map[string]string{
+			"addr":   "192.168.1.12:1044",
+			"secret": "43214132",
+		},
+	}
+	g2 := Group{Name: group2, Status: 1, ClientDns: dns, RouteInclude: route, Auth: authData}
+	err = SetGroup(&g2)
+	ast.Nil(err)
+	err = CheckUser("aaa", "bbbbbbb", group2)
+	if ast.NotNil(err) {
+		ast.Equal("aaa Radius服务器连接异常, 请检测服务器和端口", err.Error())
+
+	}
+	// 添加用户策略
+	dns2 := []ValData{{Val: "8.8.8.8"}}
+	route2 := []ValData{{Val: "192.168.2.1/24"}}
+	p1 := Policy{Username: "aaa", Status: 1, ClientDns: dns2, RouteInclude: route2}
+	err = SetPolicy(&p1)
+	ast.Nil(err)
+	err = CheckUser("aaa", u.PinCode, group)
+	ast.Nil(err)
 }
diff --git a/server/dbdata/userauth.go b/server/dbdata/userauth.go
new file mode 100644
index 0000000..fbc3eb5
--- /dev/null
+++ b/server/dbdata/userauth.go
@@ -0,0 +1,23 @@
+package dbdata
+
+import (
+	"reflect"
+	"regexp"
+)
+
+var authRegistry = make(map[string]reflect.Type)
+
+type IUserAuth interface {
+	checkData(authData map[string]interface{}) error
+	checkUser(name, pwd string, g *Group) error
+}
+
+func makeInstance(name string) interface{} {
+	v := reflect.New(authRegistry[name]).Elem()
+	return v.Interface()
+}
+
+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)
+}
diff --git a/server/dbdata/userauth_radius.go b/server/dbdata/userauth_radius.go
new file mode 100644
index 0000000..4d15eb1
--- /dev/null
+++ b/server/dbdata/userauth_radius.go
@@ -0,0 +1,72 @@
+package dbdata
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"reflect"
+	"time"
+
+	"layeh.com/radius"
+	"layeh.com/radius/rfc2865"
+)
+
+type AuthRadius struct {
+	Addr   string `json:"addr"`
+	Secret string `json:"secret"`
+}
+
+func init() {
+	authRegistry["radius"] = reflect.TypeOf(AuthRadius{})
+}
+
+func (auth AuthRadius) checkData(authData map[string]interface{}) error {
+	authType := authData["type"].(string)
+	bodyBytes, err := json.Marshal(authData[authType])
+	if err != nil {
+		return errors.New("Radius的密钥/服务器地址填写有误")
+	}
+	json.Unmarshal(bodyBytes, &auth)
+	if !ValidateIpPort(auth.Addr) {
+		return errors.New("Radius的服务器地址填写有误")
+	}
+	// freeradius官网最大8000字符, 这里限制200
+	if len(auth.Secret) < 8 || len(auth.Secret) > 200 {
+		return errors.New("Radius的密钥长度需在8~200个字符之间")
+	}
+	return nil
+}
+
+func (auth AuthRadius) checkUser(name, pwd string, g *Group) error {
+	pl := len(pwd)
+	if name == "" || pl < 1 {
+		return fmt.Errorf("%s %s", name, "密码错误")
+	}
+	authType := g.Auth["type"].(string)
+	if _, ok := g.Auth[authType]; !ok {
+		return fmt.Errorf("%s %s", name, "Radius的radius值不存在")
+	}
+	bodyBytes, err := json.Marshal(g.Auth[authType])
+	if err != nil {
+		return fmt.Errorf("%s %s", name, "Radius Marshal出现错误")
+	}
+	err = json.Unmarshal(bodyBytes, &auth)
+	if err != nil {
+		return fmt.Errorf("%s %s", name, "Radius Unmarshal出现错误")
+	}
+	// radius认证时,设置超时3秒
+	packet := radius.New(radius.CodeAccessRequest, []byte(auth.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, auth.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
+}
diff --git a/server/go.mod b/server/go.mod
index f46c1b3..4f3d552 100644
--- a/server/go.mod
+++ b/server/go.mod
@@ -25,6 +25,7 @@ require (
 	golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
 	golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d
 	golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
+	layeh.com/radius v0.0.0-20210819152912-ad72663a72ab
 	xorm.io/xorm v1.2.2
 )
 
diff --git a/server/go.sum b/server/go.sum
index 06fafa4..089a38c 100644
--- a/server/go.sum
+++ b/server/go.sum
@@ -565,6 +565,7 @@ golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
@@ -964,6 +965,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
 honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+layeh.com/radius v0.0.0-20210819152912-ad72663a72ab h1:05KeMI4s7jEdIfHb7QCjUr5X2BRA0gjLZLZEmmjGNc4=
+layeh.com/radius v0.0.0-20210819152912-ad72663a72ab/go.mod h1:pFWM9De99EY9TPVyHIyA56QmoRViVck/x41WFkUlc9A=
 lukechampine.com/uint128 v1.1.1 h1:pnxCASz787iMf+02ssImqk6OLt+Z5QHMoZyUXR4z6JU=
 lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
 modernc.org/cc/v3 v3.33.6 h1:r63dgSzVzRxUpAJFPQWHy1QeZeY1ydNENUDaBx1GqYc=
diff --git a/server/handler/link_auth.go b/server/handler/link_auth.go
index 6c98138..d1740af 100644
--- a/server/handler/link_auth.go
+++ b/server/handler/link_auth.go
@@ -221,3 +221,19 @@ var auth_profile = `<?xml version="1.0" encoding="UTF-8"?>
 	</ServerList>
 </AnyConnectProfile>
 `
+var ds_domains_xml = `
+<?xml version="1.0" encoding="UTF-8"?>
+<config-auth client="vpn" type="complete" aggregate-auth-version="2">
+    <config client="vpn" type="private">
+        <opaque is-for="vpn-client">
+            <custom-attr>
+            {{if .DsExcludeDomains}}
+               <dynamic-split-exclude-domains><![CDATA[{{.DsExcludeDomains}},]]></dynamic-split-exclude-domains>
+            {{else if .DsIncludeDomains}}
+               <dynamic-split-include-domains><![CDATA[{{.DsIncludeDomains}}]]></dynamic-split-include-domains>
+            {{end}}
+            </custom-attr>
+        </opaque>
+    </config>
+</config-auth>
+`
diff --git a/server/handler/link_tunnel.go b/server/handler/link_tunnel.go
index a43cb5f..42bf87f 100644
--- a/server/handler/link_tunnel.go
+++ b/server/handler/link_tunnel.go
@@ -8,6 +8,7 @@ import (
 	"net/http"
 	"os"
 	"strings"
+	"text/template"
 
 	"github.com/bjdgyc/anylink/base"
 	"github.com/bjdgyc/anylink/dbdata"
@@ -99,6 +100,9 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) {
 	//HttpSetHeader(w, "X-CSTP-Default-Domain", cSess.LocalIp)
 	HttpSetHeader(w, "X-CSTP-Base-MTU", cstpBaseMtu)
 
+	// 设置用户策略
+	SetUserPolicy(sess.Username, cSess.Group)
+
 	// 允许本地LAN访问vpn网络,必须放在路由的第一个
 	if cSess.Group.AllowLan {
 		HttpSetHeader(w, "X-CSTP-Split-Exclude", "0.0.0.0/255.255.255.255")
@@ -118,7 +122,6 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) {
 	for _, v := range cSess.Group.RouteExclude {
 		HttpAddHeader(w, "X-CSTP-Split-Exclude", v.IpMask)
 	}
-
 	HttpSetHeader(w, "X-CSTP-Lease-Duration", fmt.Sprintf("%d", base.Cfg.IpLease)) // ip地址租期
 	HttpSetHeader(w, "X-CSTP-Session-Timeout", "none")
 	HttpSetHeader(w, "X-CSTP-Session-Timeout-Alert-Interval", "60")
@@ -153,7 +156,11 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) {
 	HttpSetHeader(w, "X-CSTP-Disable-Always-On-VPN", "false")
 	HttpSetHeader(w, "X-CSTP-Client-Bypass-Protocol", "false")
 	HttpSetHeader(w, "X-CSTP-TCP-Keepalive", "false")
-	// HttpSetHeader(w, "X-CSTP-Post-Auth-XML", ``)
+	// 设置域名拆分隧道(移动端不支持)
+	if mobile != "mobile" {
+		SetPostAuthXml(cSess.Group, w)
+	}
+
 	w.WriteHeader(http.StatusOK)
 
 	hClone := w.Header().Clone()
@@ -187,3 +194,35 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) {
 
 	go LinkCstp(conn, bufRW, cSess)
 }
+
+// 设置域名拆分隧道
+func SetPostAuthXml(g *dbdata.Group, w http.ResponseWriter) error {
+	if g.DsExcludeDomains == "" && g.DsIncludeDomains == "" {
+		return nil
+	}
+	tmpl, err := template.New("post_auth_xml").Parse(ds_domains_xml)
+	if err != nil {
+		return err
+	}
+	var result bytes.Buffer
+	err = tmpl.Execute(&result, g)
+	if err != nil {
+		return err
+	}
+	HttpSetHeader(w, "X-CSTP-Post-Auth-XML", result.String())
+	return nil
+}
+
+// 设置用户策略, 覆盖Group的属性值
+func SetUserPolicy(username string, g *dbdata.Group) {
+	userPolicy := dbdata.GetPolicy(username)
+	if userPolicy.Id != 0 && userPolicy.Status == 1 {
+		base.Debug(username + " use UserPolicy")
+		g.AllowLan = userPolicy.AllowLan
+		g.ClientDns = userPolicy.ClientDns
+		g.RouteInclude = userPolicy.RouteInclude
+		g.RouteExclude = userPolicy.RouteExclude
+		g.DsExcludeDomains = userPolicy.DsExcludeDomains
+		g.DsIncludeDomains = userPolicy.DsIncludeDomains
+	}
+}
diff --git a/server/sessdata/session.go b/server/sessdata/session.go
index 97d6e3e..f165247 100644
--- a/server/sessdata/session.go
+++ b/server/sessdata/session.go
@@ -294,9 +294,12 @@ func (cs *ConnSession) ratePeriod() {
 	}
 }
 
-const MaxMtu = 1460
+var MaxMtu = 1460
 
 func (cs *ConnSession) SetMtu(mtu string) {
+	if base.Cfg.Mtu > 0 {
+		MaxMtu = base.Cfg.Mtu
+	}
 	cs.Mtu = MaxMtu
 
 	mi, err := strconv.Atoi(mtu)
diff --git a/web/src/layout/LayoutAside.vue b/web/src/layout/LayoutAside.vue
index fb2973c..fbb82dd 100644
--- a/web/src/layout/LayoutAside.vue
+++ b/web/src/layout/LayoutAside.vue
@@ -42,6 +42,7 @@
       </template>
 
       <el-menu-item index="/admin/user/list">用户列表</el-menu-item>
+      <el-menu-item index="/admin/user/policy">用户策略</el-menu-item>
       <el-menu-item index="/admin/user/online">在线用户</el-menu-item>
       <el-menu-item index="/admin/user/ip_map">IP映射</el-menu-item>
     </el-submenu>
diff --git a/web/src/pages/group/List.vue b/web/src/pages/group/List.vue
index 2fbb4b3..7a1b08b 100644
--- a/web/src/pages/group/List.vue
+++ b/web/src/pages/group/List.vue
@@ -1,7 +1,6 @@
 <template>
   <div>
     <el-card>
-
       <el-form :inline="true">
         <el-form-item>
           <el-button
@@ -65,7 +64,13 @@
             label="路由包含"
             width="200">
           <template slot-scope="scope">
-            <el-row v-for="(item,inx) in scope.row.route_include" :key="inx">{{ item.val }}</el-row>
+            <el-row v-for="(item,inx) in scope.row.route_include.slice(0, readMinRows)" :key="inx">{{ item.val }}</el-row>
+            <div v-if="scope.row.route_include.length > readMinRows">
+              <div v-if="readMore[`ri_${ scope.row.id }`]">
+                <el-row v-for="(item,inx) in scope.row.route_include.slice(readMinRows)" :key="inx">{{ item.val }}</el-row>              
+              </div>
+              <el-button size="mini" type="text" @click="toggleMore(`ri_${ scope.row.id }`)">{{ readMore[`ri_${ scope.row.id }`] ? "▲ 收起" : "▼ 更多" }}</el-button>              
+            </div>            
           </template>
         </el-table-column>
 
@@ -74,7 +79,13 @@
             label="路由排除"
             width="200">
           <template slot-scope="scope">
-            <el-row v-for="(item,inx) in scope.row.route_exclude" :key="inx">{{ item.val }}</el-row>
+            <el-row v-for="(item,inx) in scope.row.route_exclude.slice(0, readMinRows)" :key="inx">{{ item.val }}</el-row>
+            <div v-if="scope.row.route_exclude.length > readMinRows">
+              <div v-if="readMore[`re_${ scope.row.id }`]">
+                <el-row v-for="(item,inx) in scope.row.route_exclude.slice(readMinRows)" :key="inx">{{ item.val }}</el-row>              
+              </div>
+              <el-button size="mini" type="text" @click="toggleMore(`re_${ scope.row.id }`)">{{ readMore[`re_${ scope.row.id }`] ? "▲ 收起" : "▼ 更多" }}</el-button>              
+            </div>
           </template>
         </el-table-column>
 
@@ -83,9 +94,17 @@
             label="LINK-ACL"
             min-width="200">
           <template slot-scope="scope">
-            <el-row v-for="(item,inx) in scope.row.link_acl" :key="inx">
+            <el-row v-for="(item,inx) in scope.row.link_acl.slice(0, readMinRows)" :key="inx">
               {{ item.action }} => {{ item.val }} : {{ item.port }}
             </el-row>
+            <div v-if="scope.row.link_acl.length > readMinRows">
+              <div v-if="readMore[`la_${ scope.row.id }`]">
+                <el-row v-for="(item,inx) in scope.row.link_acl.slice(readMinRows)" :key="inx">
+                  {{ item.action }} => {{ item.val }} : {{ item.port }}
+                </el-row>
+              </div>
+              <el-button size="mini" type="text" @click="toggleMore(`la_${ scope.row.id }`)">{{ readMore[`la_${ scope.row.id }`] ? "▲ 收起" : "▼ 更多" }}</el-button>              
+            </div>
           </template>
         </el-table-column>
 
@@ -152,143 +171,175 @@
         center>
 
       <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="ruleForm">
-        <el-form-item label="用户组ID" prop="id">
-          <el-input v-model="ruleForm.id" disabled></el-input>
-        </el-form-item>
+        <el-tabs v-model="activeTab">
+           <el-tab-pane label="通用" name="general">      
+                <el-form-item label="用户组ID" prop="id">
+                <el-input v-model="ruleForm.id" disabled></el-input>
+                </el-form-item>
 
-        <el-form-item label="组名" prop="name">
-          <el-input v-model="ruleForm.name" :disabled="ruleForm.id > 0"></el-input>
-        </el-form-item>
+                <el-form-item label="组名" prop="name">
+                <el-input v-model="ruleForm.name" :disabled="ruleForm.id > 0"></el-input>
+                </el-form-item>
 
-        <el-form-item label="备注" prop="note">
-          <el-input v-model="ruleForm.note"></el-input>
-        </el-form-item>
+                <el-form-item label="备注" prop="note">
+                <el-input v-model="ruleForm.note"></el-input>
+                </el-form-item>
 
-        <el-form-item label="带宽限制" prop="bandwidth">
-          <el-input v-model.number="ruleForm.bandwidth">
-            <template slot="append">BYTE/S</template>
-          </el-input>
-        </el-form-item>
-        <el-form-item label="本地网络" prop="allow_lan">
-          <el-switch
-              v-model="ruleForm.allow_lan">
-          </el-switch>
-        </el-form-item>
+                <el-form-item label="带宽限制" prop="bandwidth">
+                <el-input v-model.number="ruleForm.bandwidth">
+                    <template slot="append">BYTE/S</template>
+                </el-input>
+                </el-form-item>
+                <el-form-item label="本地网络" prop="allow_lan">
+                <el-switch
+                    v-model="ruleForm.allow_lan">
+                </el-switch>
+                </el-form-item>
 
-        <el-form-item label="客户端DNS" prop="client_dns">
-          <el-row class="msg-info">
-            <el-col :span="20">输入IP格式如: 192.168.0.10</el-col>
-            <el-col :span="4">
-              <el-button size="mini" type="success" icon="el-icon-plus" circle
-                         @click.prevent="addDomain(ruleForm.client_dns)"></el-button>
-            </el-col>
-          </el-row>
-          <el-row v-for="(item,index) in ruleForm.client_dns"
-                  :key="index" style="margin-bottom: 5px" :gutter="10">
-            <el-col :span="10">
-              <el-input v-model="item.val"></el-input>
-            </el-col>
-            <el-col :span="12">
-              <el-input v-model="item.note" placeholder="备注"></el-input>
-            </el-col>
-            <el-col :span="2">
-              <el-button size="mini" type="danger" icon="el-icon-minus" circle
-                         @click.prevent="removeDomain(ruleForm.client_dns,index)"></el-button>
-            </el-col>
-          </el-row>
-        </el-form-item>
+                <el-form-item label="客户端DNS" prop="client_dns">
+                <el-row class="msg-info">
+                    <el-col :span="20">输入IP格式如: 192.168.0.10</el-col>
+                    <el-col :span="4">
+                    <el-button size="mini" type="success" icon="el-icon-plus" circle
+                                @click.prevent="addDomain(ruleForm.client_dns)"></el-button>
+                    </el-col>
+                </el-row>
+                <el-row v-for="(item,index) in ruleForm.client_dns"
+                        :key="index" style="margin-bottom: 5px" :gutter="10">
+                    <el-col :span="10">
+                    <el-input v-model="item.val"></el-input>
+                    </el-col>
+                    <el-col :span="12">
+                    <el-input v-model="item.note" placeholder="备注"></el-input>
+                    </el-col>
+                    <el-col :span="2">
+                    <el-button size="mini" type="danger" icon="el-icon-minus" circle
+                                @click.prevent="removeDomain(ruleForm.client_dns,index)"></el-button>
+                    </el-col>
+                </el-row>
+                </el-form-item>
+                <el-form-item label="状态" prop="status">
+                    <el-radio-group v-model="ruleForm.status">
+                        <el-radio :label="1" border>启用</el-radio>
+                        <el-radio :label="0" border>停用</el-radio>
+                    </el-radio-group>
+                </el-form-item>            
+            </el-tab-pane>
 
-        <el-form-item label="包含路由" prop="route_include">
-          <el-row class="msg-info">
-            <el-col :span="20">输入CIDR格式如: 192.168.1.0/24</el-col>
-            <el-col :span="4">
-              <el-button size="mini" type="success" icon="el-icon-plus" circle
-                         @click.prevent="addDomain(ruleForm.route_include)"></el-button>
-            </el-col>
-          </el-row>
-          <el-row v-for="(item,index) in ruleForm.route_include"
-                  :key="index" style="margin-bottom: 5px" :gutter="10">
-            <el-col :span="10">
-              <el-input v-model="item.val"></el-input>
-            </el-col>
-            <el-col :span="12">
-              <el-input v-model="item.note" placeholder="备注"></el-input>
-            </el-col>
-            <el-col :span="2">
-              <el-button size="mini" type="danger" icon="el-icon-minus" circle
-                         @click.prevent="removeDomain(ruleForm.route_include,index)"></el-button>
-            </el-col>
-          </el-row>
-        </el-form-item>
+            <el-tab-pane label="认证方式" name="authtype">
+                <el-form-item label="认证" prop="authtype">
+                    <el-radio-group v-model="ruleForm.auth.type">
+                        <el-radio label="local" border>本地</el-radio>
+                        <el-radio label="radius" border>Radius</el-radio>
+                    </el-radio-group>
+                </el-form-item>               
+                <el-form-item label="Radius密钥" v-if="ruleForm.auth.type == 'radius'">
+                    <el-col :span="10">
+                        <el-input v-model="ruleForm.auth.radius.secret"></el-input>
+                    </el-col>
+                </el-form-item>               
+                <el-form-item label="Radius服务器" v-if="ruleForm.auth.type == 'radius'">
+                    <el-col :span="10">
+                        <el-input v-model="ruleForm.auth.radius.addr" placeholder="输入IP和端口 192.168.2.1:1812"></el-input>
+                    </el-col>
+                </el-form-item>                
+            </el-tab-pane>            
 
-        <el-form-item label="排除路由" prop="route_exclude">
-          <el-row class="msg-info">
-            <el-col :span="20">输入CIDR格式如: 192.168.2.0/24</el-col>
-            <el-col :span="4">
-              <el-button size="mini" type="success" icon="el-icon-plus" circle
-                         @click.prevent="addDomain(ruleForm.route_exclude)"></el-button>
-            </el-col>
-          </el-row>
-          <el-row v-for="(item,index) in ruleForm.route_exclude"
-                  :key="index" style="margin-bottom: 5px" :gutter="10">
-            <el-col :span="10">
-              <el-input v-model="item.val"></el-input>
-            </el-col>
-            <el-col :span="12">
-              <el-input v-model="item.note" placeholder="备注"></el-input>
-            </el-col>
-            <el-col :span="2">
-              <el-button size="mini" type="danger" icon="el-icon-minus" circle
-                         @click.prevent="removeDomain(ruleForm.route_exclude,index)"></el-button>
-            </el-col>
-          </el-row>
-        </el-form-item>
+            <el-tab-pane label="路由设置" name="route">
+                <el-form-item label="包含路由" prop="route_include">
+                <el-row class="msg-info">
+                    <el-col :span="20">输入CIDR格式如: 192.168.1.0/24</el-col>
+                    <el-col :span="4">
+                    <el-button size="mini" type="success" icon="el-icon-plus" circle
+                                @click.prevent="addDomain(ruleForm.route_include)"></el-button>
+                    </el-col>
+                </el-row>
+                <el-row v-for="(item,index) in ruleForm.route_include"
+                        :key="index" style="margin-bottom: 5px" :gutter="10">
+                    <el-col :span="10">
+                    <el-input v-model="item.val"></el-input>
+                    </el-col>
+                    <el-col :span="12">
+                    <el-input v-model="item.note" placeholder="备注"></el-input>
+                    </el-col>
+                    <el-col :span="2">
+                    <el-button size="mini" type="danger" icon="el-icon-minus" circle
+                                @click.prevent="removeDomain(ruleForm.route_include,index)"></el-button>
+                    </el-col>
+                </el-row>
+                </el-form-item>
 
-        <el-form-item label="权限控制" prop="link_acl">
-          <el-row class="msg-info">
-            <el-col :span="20">输入CIDR格式如: 192.168.3.0/24 端口0表示所有端口</el-col>
-            <el-col :span="4">
-              <el-button size="mini" type="success" icon="el-icon-plus" circle
-                         @click.prevent="addDomain(ruleForm.link_acl)"></el-button>
-            </el-col>
-          </el-row>
+                <el-form-item label="排除路由" prop="route_exclude">
+                <el-row class="msg-info">
+                    <el-col :span="20">输入CIDR格式如: 192.168.2.0/24</el-col>
+                    <el-col :span="4">
+                    <el-button size="mini" type="success" icon="el-icon-plus" circle
+                                @click.prevent="addDomain(ruleForm.route_exclude)"></el-button>
+                    </el-col>
+                </el-row>
+                <el-row v-for="(item,index) in ruleForm.route_exclude"
+                        :key="index" style="margin-bottom: 5px" :gutter="10">
+                    <el-col :span="10">
+                    <el-input v-model="item.val"></el-input>
+                    </el-col>
+                    <el-col :span="12">
+                    <el-input v-model="item.note" placeholder="备注"></el-input>
+                    </el-col>
+                    <el-col :span="2">
+                    <el-button size="mini" type="danger" icon="el-icon-minus" circle
+                                @click.prevent="removeDomain(ruleForm.route_exclude,index)"></el-button>
+                    </el-col>
+                </el-row>
+                </el-form-item>
+            </el-tab-pane>
+            <el-tab-pane label="权限控制" name="link_acl">
+                <el-form-item label="权限控制" prop="link_acl">
+                <el-row class="msg-info">
+                    <el-col :span="20">输入CIDR格式如: 192.168.3.0/24 端口0表示所有端口</el-col>
+                    <el-col :span="4">
+                    <el-button size="mini" type="success" icon="el-icon-plus" circle
+                                @click.prevent="addDomain(ruleForm.link_acl)"></el-button>
+                    </el-col>
+                </el-row>
 
-          <el-row v-for="(item,index) in ruleForm.link_acl"
-                  :key="index" style="margin-bottom: 5px" :gutter="5">
-            <el-col :span="11">
-              <el-input placeholder="请输入CIDR地址" v-model="item.val">
-                <el-select v-model="item.action" slot="prepend">
-                  <el-option label="允许" value="allow"></el-option>
-                  <el-option label="禁止" value="deny"></el-option>
-                </el-select>
-              </el-input>
-            </el-col>
-            <el-col :span="3">
-              <el-input v-model.number="item.port" placeholder="端口"></el-input>
-            </el-col>
-            <el-col :span="8">
-              <el-input v-model="item.note" placeholder="备注"></el-input>
-            </el-col>
-            <el-col :span="2">
-              <el-button size="mini" type="danger" icon="el-icon-minus" circle
-                         @click.prevent="removeDomain(ruleForm.link_acl,index)"></el-button>
-            </el-col>
-          </el-row>
-        </el-form-item>
+                <el-row v-for="(item,index) in ruleForm.link_acl"
+                        :key="index" style="margin-bottom: 5px" :gutter="5">
+                    <el-col :span="11">
+                    <el-input placeholder="请输入CIDR地址" v-model="item.val">
+                        <el-select v-model="item.action" slot="prepend">
+                        <el-option label="允许" value="allow"></el-option>
+                        <el-option label="禁止" value="deny"></el-option>
+                        </el-select>
+                    </el-input>
+                    </el-col>
+                    <el-col :span="3">
+                    <el-input v-model.number="item.port" placeholder="端口"></el-input>
+                    </el-col>
+                    <el-col :span="8">
+                    <el-input v-model="item.note" placeholder="备注"></el-input>
+                    </el-col>
+                    <el-col :span="2">
+                    <el-button size="mini" type="danger" icon="el-icon-minus" circle
+                                @click.prevent="removeDomain(ruleForm.link_acl,index)"></el-button>
+                    </el-col>
+                </el-row>
+                </el-form-item>
+            </el-tab-pane>
 
-        <el-form-item label="状态" prop="status">
-          <el-radio-group v-model="ruleForm.status">
-            <el-radio :label="1" border>启用</el-radio>
-            <el-radio :label="0" border>停用</el-radio>
-          </el-radio-group>
-
-        </el-form-item>
-
-        <el-form-item>
-          <el-button type="primary" @click="submitForm('ruleForm')">保存</el-button>
-          <el-button @click="disVisible">取消</el-button>
-        </el-form-item>
-      </el-form>
+            <el-tab-pane label="域名拆分隧道" name="ds_domains">
+                <el-form-item label="包含域名" prop="ds_include_domains">
+                    <el-input type="textarea" :rows="5" v-model="ruleForm.ds_include_domains" placeholder="输入域名用,号分隔,默认匹配所有子域名, 如baidu.com,163.com"></el-input>
+                </el-form-item>                
+                <el-form-item label="排除域名" prop="ds_exclude_domains">
+                    <el-input type="textarea" :rows="5" v-model="ruleForm.ds_exclude_domains" placeholder="输入域名用,号分隔,默认匹配所有子域名, 如baidu.com,163.com"></el-input>
+                </el-form-item>
+            </el-tab-pane>
+            <el-form-item>
+            <el-button type="primary" @click="submitForm('ruleForm')">保存</el-button>
+            <el-button @click="disVisible">取消</el-button>
+            </el-form-item>
+          </el-tabs>
+        </el-form> 
     </el-dialog>
 
   </div>
@@ -306,14 +357,17 @@ export default {
     this.$emit('update:route_name', ['用户组信息', '用户组列表'])
   },
   mounted() {
-    this.getData(1)
+    this.getData(1);
+    this.setAuthData();
   },
   data() {
     return {
       page: 1,
       tableData: [],
       count: 10,
-
+      activeTab : "general",
+      readMore: {},
+      readMinRows : 5,
       ruleForm: {
         bandwidth: 0,
         status: 1,
@@ -322,21 +376,17 @@ export default {
         route_include: [{val: 'all', note: '默认全局代理'}],
         route_exclude: [],
         link_acl: [],
+        auth : {"type":'local'}
       },
       rules: {
         name: [
-          {required: true, message: '请输入用户名', trigger: 'blur'},
+          {required: true, message: '请输入组名', trigger: 'blur'},
           {max: 30, message: '长度小于 30 个字符', trigger: 'blur'}
         ],
         bandwidth: [
-          {required: true, message: '请输入用户姓名', trigger: 'blur'},
-          {type: 'number', message: '年龄必须为数字值'}
+          {required: true, message: '请输入带宽限制', trigger: 'blur'},
+          {type: 'number', message: '带宽限制必须为数字值'}
         ],
-        email: [
-          {required: true, message: '请输入用户邮箱', trigger: 'blur'},
-          {type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change']}
-        ],
-
         status: [
           {required: true}
         ],
@@ -344,6 +394,14 @@ export default {
     }
   },
   methods: {
+    setAuthData(row) {
+        var defAuthData = {"type":'local', 
+                           "radius":{"addr":"", "secret":""},
+                          }
+        if (this.ruleForm.auth.type == "local" || !row) {
+            this.ruleForm.auth = defAuthData;
+        }
+    },
     handleDel(row) {
       axios.post('/group/del?id=' + row.id).then(resp => {
         const rdata = resp.data;
@@ -362,17 +420,19 @@ export default {
     handleEdit(row) {
       !this.$refs['ruleForm'] || this.$refs['ruleForm'].resetFields();
       console.log(row)
+      this.activeTab = "general"
       this.user_edit_dialog = true
       if (!row) {
+        this.setAuthData(row)
         return;
       }
-
       axios.get('/group/detail', {
         params: {
           id: row.id,
         }
       }).then(resp => {
-        this.ruleForm = resp.data.data
+        this.ruleForm = resp.data.data;
+        this.setAuthData(resp.data.data);
       }).catch(error => {
         this.$message.error('哦,请求出错');
         console.log(error);
@@ -417,7 +477,6 @@ export default {
           console.log('error submit!!');
           return false;
         }
-
         axios.post('/group/set', this.ruleForm).then(resp => {
           const rdata = resp.data;
           if (rdata.code === 0) {
@@ -436,9 +495,15 @@ export default {
     },
     resetForm(formName) {
       this.$refs[formName].resetFields();
-    }
+    },
+    toggleMore(id) {
+      if (this.readMore[id]) {
+        this.$set(this.readMore, id, false);
+      } else {
+        this.$set(this.readMore, id, true);
+      }
+    },
   },
-
 }
 </script>
 
diff --git a/web/src/pages/user/Policy.vue b/web/src/pages/user/Policy.vue
new file mode 100644
index 0000000..b2a852e
--- /dev/null
+++ b/web/src/pages/user/Policy.vue
@@ -0,0 +1,421 @@
+<template>
+  <div>
+    <el-card>
+      <el-form :inline="true">
+        <el-form-item>
+          <el-button
+              size="small"
+              type="primary"
+              icon="el-icon-plus"
+              @click="handleEdit('')">添加
+          </el-button>
+        </el-form-item>
+      </el-form>
+
+      <el-table
+          ref="multipleTable"
+          :data="tableData"
+          border>
+
+        <el-table-column
+            sortable="true"
+            prop="id"
+            label="ID"
+            width="60">
+        </el-table-column>
+
+        <el-table-column
+            prop="username"
+            label="用户名">
+        </el-table-column>
+        <el-table-column
+            prop="allow_lan"
+            label="本地网络">
+          <template slot-scope="scope">
+            <el-switch
+                v-model="scope.row.allow_lan"
+                disabled>
+            </el-switch>
+          </template>
+        </el-table-column>
+
+        <el-table-column
+            prop="client_dns"
+            label="客户端DNS"
+            width="160">
+          <template slot-scope="scope">
+            <el-row v-for="(item,inx) in scope.row.client_dns" :key="inx">{{ item.val }}</el-row>
+          </template>
+        </el-table-column>
+
+        <el-table-column
+            prop="route_include"
+            label="路由包含"
+            width="200">
+          <template slot-scope="scope">
+            <el-row v-for="(item,inx) in scope.row.route_include.slice(0, readMinRows)" :key="inx">{{ item.val }}</el-row>
+            <div v-if="scope.row.route_include.length > readMinRows">
+              <div v-if="readMore[`ri_${ scope.row.id }`]">
+                <el-row v-for="(item,inx) in scope.row.route_include.slice(readMinRows)" :key="inx">{{ item.val }}</el-row>              
+              </div>
+              <el-button size="mini" type="text" @click="toggleMore(`ri_${ scope.row.id }`)">{{ readMore[`ri_${ scope.row.id }`] ? "▲ 收起" : "▼ 更多" }}</el-button>              
+            </div>            
+          </template>
+        </el-table-column>
+
+        <el-table-column
+            prop="route_exclude"
+            label="路由排除"
+            width="200">
+          <template slot-scope="scope">
+            <el-row v-for="(item,inx) in scope.row.route_exclude.slice(0, readMinRows)" :key="inx">{{ item.val }}</el-row>
+            <div v-if="scope.row.route_exclude.length > readMinRows">
+              <div v-if="readMore[`re_${ scope.row.id }`]">
+                <el-row v-for="(item,inx) in scope.row.route_exclude.slice(readMinRows)" :key="inx">{{ item.val }}</el-row>              
+              </div>
+              <el-button size="mini" type="text" @click="toggleMore(`re_${ scope.row.id }`)">{{ readMore[`re_${ scope.row.id }`] ? "▲ 收起" : "▼ 更多" }}</el-button>              
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column
+            prop="status"
+            label="状态"
+            width="70">
+          <template slot-scope="scope">
+            <el-tag v-if="scope.row.status === 1" type="success">可用</el-tag>
+            <el-tag v-else type="danger">停用</el-tag>
+          </template>
+
+        </el-table-column>
+
+        <el-table-column
+            prop="updated_at"
+            label="更新时间"
+            :formatter="tableDateFormat">
+        </el-table-column>
+
+        <el-table-column
+            label="操作"
+            width="150">
+          <template slot-scope="scope">
+            <el-button
+                size="mini"
+                type="primary"
+                @click="handleEdit(scope.row)">编辑
+            </el-button>
+
+            <el-popconfirm
+                style="margin-left: 10px"
+                @confirm="handleDel(scope.row)"
+                title="确定要删除用户策略项吗?">
+              <el-button
+                  slot="reference"
+                  size="mini"
+                  type="danger">删除
+              </el-button>
+            </el-popconfirm>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <el-pagination
+          background
+          layout="prev, pager, next"
+          :pager-count="11"
+          @current-change="pageChange"
+          :current-page="page"
+          :total="count">
+      </el-pagination>
+
+    </el-card>
+
+    <!--新增、修改弹出框-->
+    <el-dialog
+        :close-on-click-modal="false"
+        title="用户策略"
+        :visible.sync="user_edit_dialog"
+        width="750px"
+        top="50px"
+        center>
+
+      <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="ruleForm">
+        <el-tabs v-model="activeTab">
+           <el-tab-pane label="通用" name="general">
+                <el-form-item label="ID" prop="id">
+                <el-input v-model="ruleForm.id" disabled></el-input>
+                </el-form-item>
+
+                <el-form-item label="用户名" prop="username">
+                <el-input v-model="ruleForm.username" :disabled="ruleForm.id > 0"></el-input>
+                </el-form-item>
+
+                <el-form-item label="本地网络" prop="allow_lan">
+                  <el-switch
+                      v-model="ruleForm.allow_lan">
+                  </el-switch>
+                </el-form-item>
+                <el-form-item label="客户端DNS" prop="client_dns">
+                    <el-row class="msg-info">
+                        <el-col :span="20">输入IP格式如: 192.168.0.10</el-col>
+                        <el-col :span="4">
+                        <el-button size="mini" type="success" icon="el-icon-plus" circle
+                                    @click.prevent="addDomain(ruleForm.client_dns)"></el-button>
+                        </el-col>
+                    </el-row>
+                    <el-row v-for="(item,index) in ruleForm.client_dns"
+                            :key="index" style="margin-bottom: 5px" :gutter="10">
+                        <el-col :span="10">
+                        <el-input v-model="item.val"></el-input>
+                        </el-col>
+                        <el-col :span="12">
+                        <el-input v-model="item.note" placeholder="备注"></el-input>
+                        </el-col>
+                        <el-col :span="2">
+                        <el-button size="mini" type="danger" icon="el-icon-minus" circle
+                                    @click.prevent="removeDomain(ruleForm.client_dns,index)"></el-button>
+                        </el-col>
+                    </el-row>
+                </el-form-item>
+                <el-form-item label="状态" prop="status">
+                    <el-radio-group v-model="ruleForm.status">
+                        <el-radio :label="1" border>启用</el-radio>
+                        <el-radio :label="0" border>停用</el-radio>
+                    </el-radio-group>
+                </el-form-item>                
+            </el-tab-pane>
+
+            <el-tab-pane label="路由设置" name="route">
+                <el-form-item label="包含路由" prop="route_include">
+                    <el-row class="msg-info">
+                        <el-col :span="20">输入CIDR格式如: 192.168.1.0/24</el-col>
+                        <el-col :span="4">
+                        <el-button size="mini" type="success" icon="el-icon-plus" circle
+                                    @click.prevent="addDomain(ruleForm.route_include)"></el-button>
+                        </el-col>
+                    </el-row>
+                    <el-row v-for="(item,index) in ruleForm.route_include"
+                            :key="index" style="margin-bottom: 5px" :gutter="10">
+                        <el-col :span="10">
+                        <el-input v-model="item.val"></el-input>
+                        </el-col>
+                        <el-col :span="12">
+                        <el-input v-model="item.note" placeholder="备注"></el-input>
+                        </el-col>
+                        <el-col :span="2">
+                        <el-button size="mini" type="danger" icon="el-icon-minus" circle
+                                    @click.prevent="removeDomain(ruleForm.route_include,index)"></el-button>
+                        </el-col>
+                    </el-row>      
+                </el-form-item>
+
+                <el-form-item label="排除路由" prop="route_exclude">
+                    <el-row class="msg-info">
+                        <el-col :span="20">输入CIDR格式如: 192.168.2.0/24</el-col>
+                        <el-col :span="4">
+                        <el-button size="mini" type="success" icon="el-icon-plus" circle
+                                    @click.prevent="addDomain(ruleForm.route_exclude)"></el-button>
+                        </el-col>
+                    </el-row>
+                    <el-row v-for="(item,index) in ruleForm.route_exclude"
+                            :key="index" style="margin-bottom: 5px" :gutter="10">
+                        <el-col :span="10">
+                        <el-input v-model="item.val"></el-input>
+                        </el-col>
+                        <el-col :span="12">
+                        <el-input v-model="item.note" placeholder="备注"></el-input>
+                        </el-col>
+                        <el-col :span="2">
+                        <el-button size="mini" type="danger" icon="el-icon-minus" circle
+                                    @click.prevent="removeDomain(ruleForm.route_exclude,index)"></el-button>
+                        </el-col>
+                    </el-row>
+                </el-form-item> 
+            </el-tab-pane>
+            
+            <el-tab-pane label="动态拆分隧道" name="ds_domains">
+                <el-form-item label="包含域名" prop="ds_include_domains">
+                    <el-input type="textarea" :rows="5" v-model="ruleForm.ds_include_domains"></el-input>
+                </el-form-item>                
+                <el-form-item label="排除域名" prop="ds_exclude_domains">
+                    <el-input type="textarea" :rows="5" v-model="ruleForm.ds_exclude_domains"></el-input>
+                </el-form-item>
+            </el-tab-pane>
+        </el-tabs>
+        <el-form-item>
+            <el-button type="primary" @click="submitForm('ruleForm')">保存</el-button>
+            <el-button @click="disVisible">取消</el-button>
+        </el-form-item>
+      </el-form>
+    </el-dialog>
+</div>
+  
+</template>
+
+<script>
+import axios from "axios";
+
+export default {
+  name: "Policy",
+  components: {},
+  mixins: [],
+  created() {
+    this.$emit('update:route_path', this.$route.path)
+    this.$emit('update:route_name', ['用户信息', '用户策略'])
+  },
+  mounted() {
+    this.getData(1)
+  },
+  data() {
+    return {
+      page: 1,
+      tableData: [],
+      count: 10,
+      activeTab : "general",
+      readMore: {},
+      readMinRows : 5,      
+      ruleForm: {
+        bandwidth: 0,
+        status: 1,
+        allow_lan: true,
+        client_dns: [{val: '114.114.114.114'}],
+        route_include: [{val: 'all', note: '默认全局代理'}],
+        route_exclude: [],
+        re_upper_limit : 0,        
+      },
+      rules: {
+        name: [
+          {required: true, message: '请输入用户名', trigger: 'blur'},
+          {max: 30, message: '长度小于 30 个字符', trigger: 'blur'}
+        ],
+        bandwidth: [
+          {required: true, message: '请输入带宽限制', trigger: 'blur'},
+          {type: 'number', message: '带宽必须为数字值'}
+        ],
+        status: [
+          {required: true}
+        ],       
+      },
+    }
+  },
+  methods: {
+    handleDel(row) {
+      axios.post('/user/policy/del?id=' + row.id).then(resp => {
+        const rdata = resp.data;
+        if (rdata.code === 0) {
+          this.$message.success(rdata.msg);
+          this.getData(1);
+        } else {
+          this.$message.error(rdata.msg);
+        }
+        console.log(rdata);
+      }).catch(error => {
+        this.$message.error('哦,请求出错');
+        console.log(error);
+      });
+    },
+    handleEdit(row) {
+      !this.$refs['ruleForm'] || this.$refs['ruleForm'].resetFields();
+      console.log(row)
+      this.activeTab = "general"
+      this.user_edit_dialog = true
+      if (!row) {
+        return;
+      }
+
+      axios.get('/user/policy/detail', {
+        params: {
+          id: row.id,
+        }
+      }).then(resp => {
+        this.ruleForm = resp.data.data
+      }).catch(error => {
+        this.$message.error('哦,请求出错');
+        console.log(error);
+      });
+    },
+    pageChange(p) {
+      this.getData(p)
+    },
+    getData(page) {
+      this.page = page
+      axios.get('/user/policy/list', {
+        params: {
+          page: page,
+        }
+      }).then(resp => {
+        const rdata = resp.data.data;
+        console.log(rdata);
+        this.tableData = rdata.datas;
+        this.count = rdata.count
+      }).catch(error => {
+        this.$message.error('哦,请求出错');
+        console.log(error);
+      });
+    },
+    removeDomain(arr, index) {
+      console.log(index)
+      if (index >= 0 && index < arr.length) {
+        arr.splice(index, 1)
+      }
+      // let index = arr.indexOf(item);
+      // if (index !== -1 && arr.length > 1) {
+      //   arr.splice(index, 1)
+      // }
+      // arr.pop()
+    },
+    addDomain(arr) {
+      arr.push({val: "", action: "allow", port: 0});
+    },
+    submitForm(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (!valid) {
+          console.log('error submit!!');
+          return false;
+        }
+
+        axios.post('/user/policy/set', this.ruleForm).then(resp => {
+          const rdata = resp.data;
+          if (rdata.code === 0) {
+            this.$message.success(rdata.msg);
+            this.getData(1);
+            this.user_edit_dialog = false
+          } else {
+            this.$message.error(rdata.msg);
+          }
+          console.log(rdata);
+        }).catch(error => {
+          this.$message.error('哦,请求出错');
+          console.log(error);
+        });
+      });
+    },
+    resetForm(formName) {
+      this.$refs[formName].resetFields();
+    },
+    toggleMore(id) {
+      if (this.readMore[id]) {
+        this.$set(this.readMore, id, false);
+      } else {
+        this.$set(this.readMore, id, true);
+      }
+    },    
+  },
+
+}
+</script>
+
+<style scoped>
+.msg-info {
+  background-color: #f4f4f5;
+  color: #909399;
+  padding: 0 5px;
+  margin: 0;
+  box-sizing: border-box;
+  border-radius: 4px;
+  font-size: 12px;
+}
+
+.el-select {
+  width: 80px;
+}
+</style>
diff --git a/web/src/plugins/mixin.js b/web/src/plugins/mixin.js
index 2ade4fa..274e7fd 100644
--- a/web/src/plugins/mixin.js
+++ b/web/src/plugins/mixin.js
@@ -5,9 +5,9 @@ function gDateFormat(p) {
     var year = da.getFullYear();
     var month = da.getMonth() + 1;
     var dt = da.getDate();
-    var h = da.getHours();
-    var m = da.getMinutes();
-    var s = da.getSeconds();
+    var h = ('0'+da.getHours()).slice(-2);
+    var m = ('0'+da.getMinutes()).slice(-2)
+    var s = ('0'+da.getSeconds()).slice(-2);
 
     return year + '-' + month + '-' + dt + ' ' + h + ':' + m + ':' + s;
 }
diff --git a/web/src/plugins/router.js b/web/src/plugins/router.js
index f574b08..07b42e5 100644
--- a/web/src/plugins/router.js
+++ b/web/src/plugins/router.js
@@ -20,6 +20,7 @@ const routes = [
             {path: 'set/audit', component: () => import('@/pages/set/Audit')},
 
             {path: 'user/list', component: () => import('@/pages/user/List')},
+            {path: 'user/policy', component: () => import('@/pages/user/Policy')},
             {path: 'user/online', component: () => import('@/pages/user/Online')},
             {path: 'user/ip_map', component: () => import('@/pages/user/IpMap')},