Compare commits

...

5 Commits

Author SHA1 Message Date
刘祥超
1d22125d6e 管理员也支持AccessKey 2021-06-20 19:23:02 +08:00
刘祥超
d4689571cb 优化界面 2021-06-19 22:20:15 +08:00
刘祥超
cb1cb62e30 访问控制支持基本认证和子请求认证 2021-06-19 21:35:38 +08:00
刘祥超
77ad860d35 阶段性提交 2021-06-17 21:17:43 +08:00
刘祥超
5082561dc9 调整版本为0.2.3 2021-06-17 18:46:07 +08:00
42 changed files with 1349 additions and 59 deletions

View File

@@ -10,7 +10,8 @@
## 文档
* [新手指南](https://edge.teaos.cn/docs/QuickStart/Index.md)
* [文档](http://edge.teaos.cn/docs)
* [完整文档](https://edge.teaos.cn/docs)
* [开发者指南](https://edge.teaos.cn/docs/Developer/Build.md)
## 架构
![架构](doc/architect-zh.jpg)

8
go.mod
View File

@@ -9,12 +9,16 @@ require (
github.com/cespare/xxhash v1.1.0
github.com/go-sql-driver/mysql v1.5.0
github.com/go-yaml/yaml v2.1.0+incompatible
github.com/google/go-cmp v0.5.6 // indirect
github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f
github.com/miekg/dns v1.1.35
github.com/shirou/gopsutil v3.21.5+incompatible // indirect
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/tealeg/xlsx/v3 v3.2.3
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c
google.golang.org/grpc v1.32.0
golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced // indirect
google.golang.org/grpc v1.38.0
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
)

43
go.sum
View File

@@ -13,6 +13,7 @@ github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -20,6 +21,7 @@ github.com/dgryski/go-rendezvous v0.0.0-20200624174652-8d2f3be8b2d9/go.mod h1:cu
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/frankban/quicktest v1.5.0 h1:Tb4jWdSpdjKzTUicPnY61PZxKbDoGa7ABbrReT3gQVY=
github.com/frankban/quicktest v1.5.0/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
@@ -44,6 +46,9 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -52,7 +57,11 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f h1:r2O8PONj/KiuZjJHVHn7KlCePUIjNtgAmvLfgRafQ8o=
github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
@@ -91,18 +100,22 @@ github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/shabbyrobe/xmlwriter v0.0.0-20200208144257-9fca06d00ffa h1:2cO3RojjYl3hVTbEvJVqrMaFmORhL6O06qdW42toftk=
github.com/shabbyrobe/xmlwriter v0.0.0-20200208144257-9fca06d00ffa/go.mod h1:Yjr3bdWaVWyME1kha7X0jsz3k2DgXNa1Pj3XGyUAbx8=
github.com/shirou/gopsutil v3.21.5+incompatible h1:OloQyEerMi7JUrXiNzy8wQ5XN+baemxSl12QgIzt0jc=
github.com/shirou/gopsutil v3.21.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tealeg/xlsx/v3 v3.2.3 h1:MXnVh+9Y8cUglowItTy2HL3Kv6z+q/0aNjeKuTsVqZQ=
github.com/tealeg/xlsx/v3 v3.2.3/go.mod h1:0hGmAEoZ48SS1ZAE6eqZJkJVXgOMY+8a33vjXa8S8HA=
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119 h1:YyPWX3jLOtYKulBR6AScGIs74lLrJcgeKRwcbAuQOG4=
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119/go.mod h1:/nuTSlK+okRfR/vnIPqR89fFKonnWPiZymN5ydRJkX8=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.opentelemetry.io/otel v0.7.0/go.mod h1:aZMyHG5TqDOXEgH2tyLiXSUKly1jT3yqE9PmrzIeCdo=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
@@ -115,9 +128,11 @@ golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+o
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -128,11 +143,15 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -148,19 +167,35 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c=
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
@@ -168,6 +203,8 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced h1:c5geK1iMU3cDKtFrCVQIcjR3W+JOZMuhIyICMCTbtus=
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
@@ -175,6 +212,8 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0=
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -185,6 +224,9 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
@@ -192,6 +234,7 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@@ -1,7 +1,7 @@
package teaconst
const (
Version = "0.2.2"
Version = "0.2.3"
ProductName = "Edge Admin"
ProcessName = "edge-admin"

View File

@@ -228,6 +228,10 @@ func (this *RPCClient) HTTPFastcgiRPC() pb.HTTPFastcgiServiceClient {
return pb.NewHTTPFastcgiServiceClient(this.pickConn())
}
func (this *RPCClient) HTTPAuthPolicyRPC() pb.HTTPAuthPolicyServiceClient {
return pb.NewHTTPAuthPolicyServiceClient(this.pickConn())
}
func (this *RPCClient) SSLCertRPC() pb.SSLCertServiceClient {
return pb.NewSSLCertServiceClient(this.pickConn())
}

View File

@@ -0,0 +1,49 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package accesskeys
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
)
type CreatePopupAction struct {
actionutils.ParentAction
}
func (this *CreatePopupAction) Init() {
this.Nav("", "", "")
}
func (this *CreatePopupAction) RunGet(params struct {
AdminId int64
}) {
this.Data["adminId"] = params.AdminId
this.Show()
}
func (this *CreatePopupAction) RunPost(params struct {
AdminId int64
Description string
Must *actions.Must
CSRF *actionutils.CSRF
}) {
params.Must.
Field("description", params.Description).
Require("请输入备注")
accessKeyIdResp, err := this.RPC().UserAccessKeyRPC().CreateUserAccessKey(this.AdminContext(), &pb.CreateUserAccessKeyRequest{
AdminId: params.AdminId,
Description: params.Description,
})
if err != nil {
this.ErrorPage(err)
return
}
defer this.CreateLogInfo("创建AccessKey %d", accessKeyIdResp.UserAccessKeyId)
this.Success()
}

View File

@@ -0,0 +1,24 @@
package accesskeys
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type DeleteAction struct {
actionutils.ParentAction
}
func (this *DeleteAction) RunPost(params struct {
AccessKeyId int64
}) {
defer this.CreateLogInfo("删除AccessKey %d", params.AccessKeyId)
_, err := this.RPC().UserAccessKeyRPC().DeleteUserAccessKey(this.AdminContext(), &pb.DeleteUserAccessKeyRequest{UserAccessKeyId: params.AccessKeyId})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,54 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package accesskeys
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/admins/adminutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "", "accessKey")
}
func (this *IndexAction) RunGet(params struct {
AdminId int64
}) {
err := adminutils.InitAdmin(this.Parent(), params.AdminId)
if err != nil {
this.ErrorPage(err)
return
}
accessKeysResp, err := this.RPC().UserAccessKeyRPC().FindAllEnabledUserAccessKeys(this.AdminContext(), &pb.FindAllEnabledUserAccessKeysRequest{AdminId: params.AdminId})
if err != nil {
this.ErrorPage(err)
return
}
accessKeyMaps := []maps.Map{}
for _, accessKey := range accessKeysResp.UserAccessKeys {
var accessedTime string
if accessKey.AccessedAt > 0 {
accessedTime = timeutil.FormatTime("Y-m-d H:i:s", accessKey.AccessedAt)
}
accessKeyMaps = append(accessKeyMaps, maps.Map{
"id": accessKey.Id,
"isOn": accessKey.IsOn,
"uniqueId": accessKey.UniqueId,
"secret": accessKey.Secret,
"description": accessKey.Description,
"accessedTime": accessedTime,
})
}
this.Data["accessKeys"] = accessKeyMaps
this.Show()
}

View File

@@ -0,0 +1,28 @@
package accesskeys
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type UpdateIsOnAction struct {
actionutils.ParentAction
}
func (this *UpdateIsOnAction) RunPost(params struct {
AccessKeyId int64
IsOn bool
}) {
defer this.CreateLogInfo("设置AccessKey %d 启用状态", params.AccessKeyId)
_, err := this.RPC().UserAccessKeyRPC().UpdateUserAccessKeyIsOn(this.AdminContext(), &pb.UpdateUserAccessKeyIsOnRequest{
UserAccessKeyId: params.AccessKeyId,
IsOn: params.IsOn,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -30,13 +30,22 @@ func (this *AdminAction) RunGet(params struct {
return
}
// AccessKey数量
countAccessKeyResp, err := this.RPC().UserAccessKeyRPC().CountAllEnabledUserAccessKeys(this.AdminContext(), &pb.CountAllEnabledUserAccessKeysRequest{AdminId: params.AdminId})
if err != nil {
this.ErrorPage(err)
return
}
countAccessKeys := countAccessKeyResp.Count
this.Data["admin"] = maps.Map{
"id": admin.Id,
"fullname": admin.Fullname,
"username": admin.Username,
"isOn": admin.IsOn,
"isSuper": admin.IsSuper,
"canLogin": admin.CanLogin,
"id": admin.Id,
"fullname": admin.Fullname,
"username": admin.Username,
"isOn": admin.IsOn,
"isSuper": admin.IsSuper,
"canLogin": admin.CanLogin,
"countAccessKeys": countAccessKeys,
}
// 权限

View File

@@ -0,0 +1,38 @@
package adminutils
import (
"errors"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
// InitAdmin 查找管理员基本信息
func InitAdmin(p *actionutils.ParentAction, adminId int64) error {
// 管理员信息
resp, err := p.RPC().AdminRPC().FindEnabledAdmin(p.AdminContext(), &pb.FindEnabledAdminRequest{AdminId: adminId})
if err != nil {
return err
}
if resp.Admin == nil {
return errors.New("not found admin")
}
var admin = resp.Admin
// AccessKey数量
countAccessKeysResp, err := p.RPC().UserAccessKeyRPC().CountAllEnabledUserAccessKeys(p.AdminContext(), &pb.CountAllEnabledUserAccessKeysRequest{
AdminId: adminId,
UserId: 0,
})
if err != nil {
return err
}
p.Data["admin"] = maps.Map{
"id": admin.Id,
"username": admin.Username,
"fullname": admin.Fullname,
"countAccessKeys": countAccessKeysResp.Count,
}
return nil
}

View File

@@ -2,6 +2,7 @@ package admins
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/admins/accesskeys"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo"
)
@@ -19,6 +20,15 @@ func init() {
Get("/admin", new(AdminAction)).
Get("/otpQrcode", new(OtpQrcodeAction)).
Post("/options", new(OptionsAction)).
// AccessKeys
Prefix("/admins/accessKeys").
Get("", new(accesskeys.IndexAction)).
GetPost("/createPopup", new(accesskeys.CreatePopupAction)).
Post("/delete", new(accesskeys.DeleteAction)).
Post("/updateIsOn", new(accesskeys.UpdateIsOnAction)).
EndAll()
})
}

View File

@@ -39,14 +39,23 @@ func (this *UpdateAction) RunGet(params struct {
otpLoginIsOn = admin.OtpLogin.IsOn
}
// AccessKey数量
countAccessKeyResp, err := this.RPC().UserAccessKeyRPC().CountAllEnabledUserAccessKeys(this.AdminContext(), &pb.CountAllEnabledUserAccessKeysRequest{AdminId: params.AdminId})
if err != nil {
this.ErrorPage(err)
return
}
countAccessKeys := countAccessKeyResp.Count
this.Data["admin"] = maps.Map{
"id": admin.Id,
"fullname": admin.Fullname,
"username": admin.Username,
"isOn": admin.IsOn,
"isSuper": admin.IsSuper,
"canLogin": admin.CanLogin,
"otpLoginIsOn": otpLoginIsOn,
"id": admin.Id,
"fullname": admin.Fullname,
"username": admin.Username,
"isOn": admin.IsOn,
"isSuper": admin.IsSuper,
"canLogin": admin.CanLogin,
"otpLoginIsOn": otpLoginIsOn,
"countAccessKeys": countAccessKeys,
}
// 权限

View File

@@ -0,0 +1,123 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package access
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/actions"
)
type CreatePopupAction struct {
actionutils.ParentAction
}
func (this *CreatePopupAction) Init() {
this.Nav("", "", "")
}
func (this *CreatePopupAction) RunGet(params struct{}) {
this.Data["authTypes"] = serverconfigs.FindAllHTTPAuthTypes()
this.Show()
}
func (this *CreatePopupAction) RunPost(params struct {
Name string
Type string
// BasicAuth
HttpAuthBasicAuthUsersJSON []byte
BasicAuthRealm string
BasicAuthCharset string
// SubRequest
SubRequestURL string
SubRequestMethod string
SubRequestFollowRequest bool
Must *actions.Must
CSRF *actionutils.CSRF
}) {
params.Must.
Field("name", params.Name).
Require("请输入名称").
Field("type", params.Type).
Require("请输入认证类型")
var ref = &serverconfigs.HTTPAuthPolicyRef{IsOn: true}
var paramsJSON []byte
switch params.Type {
case serverconfigs.HTTPAuthTypeBasicAuth:
users := []*serverconfigs.HTTPAuthBasicMethodUser{}
err := json.Unmarshal(params.HttpAuthBasicAuthUsersJSON, &users)
if err != nil {
this.ErrorPage(err)
return
}
if len(users) == 0 {
this.Fail("请添加至少一个用户")
}
method := &serverconfigs.HTTPAuthBasicMethod{
Users: users,
Realm: params.BasicAuthRealm,
Charset: params.BasicAuthCharset,
}
methodJSON, err := json.Marshal(method)
if err != nil {
this.ErrorPage(err)
return
}
paramsJSON = methodJSON
case serverconfigs.HTTPAuthTypeSubRequest:
params.Must.Field("subRequestURL", params.SubRequestURL).
Require("请输入子请求URL")
if params.SubRequestFollowRequest {
params.SubRequestMethod = ""
}
method := &serverconfigs.HTTPAuthSubRequestMethod{
URL: params.SubRequestURL,
Method: params.SubRequestMethod,
}
methodJSON, err := json.Marshal(method)
if err != nil {
this.ErrorPage(err)
return
}
paramsJSON = methodJSON
default:
this.Fail("不支持的认证类型'" + params.Type + "'")
}
var paramsMap map[string]interface{}
err := json.Unmarshal(paramsJSON, &paramsMap)
if err != nil {
this.ErrorPage(err)
return
}
createResp, err := this.RPC().HTTPAuthPolicyRPC().CreateHTTPAuthPolicy(this.AdminContext(), &pb.CreateHTTPAuthPolicyRequest{
Name: params.Name,
Type: params.Type,
ParamsJSON: paramsJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
defer this.CreateLogInfo("创建HTTP认证 %d", createResp.HttpAuthPolicyId)
ref.AuthPolicyId = createResp.HttpAuthPolicyId
ref.AuthPolicy = &serverconfigs.HTTPAuthPolicy{
Id: createResp.HttpAuthPolicyId,
Name: params.Name,
IsOn: true,
Type: params.Type,
Params: paramsMap,
}
this.Data["policyRef"] = ref
this.Success()
}

View File

@@ -1,7 +1,12 @@
package access
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/actions"
)
type IndexAction struct {
@@ -16,7 +21,56 @@ func (this *IndexAction) Init() {
func (this *IndexAction) RunGet(params struct {
ServerId int64
}) {
// TODO
webConfig, err := dao.SharedHTTPWebDAO.FindWebConfigWithServerId(this.AdminContext(), params.ServerId)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["webId"] = webConfig.Id
this.Data["authConfig"] = webConfig.Auth
this.Show()
}
func (this *IndexAction) RunPost(params struct {
WebId int64
AuthJSON []byte
Must *actions.Must
CSRF *actionutils.CSRF
}) {
defer this.CreateLogInfo("修改Web %d 的认证设置", params.WebId)
var authConfig = &serverconfigs.HTTPAuthConfig{}
err := json.Unmarshal(params.AuthJSON, authConfig)
if err != nil {
this.ErrorPage(err)
return
}
err = authConfig.Init()
if err != nil {
this.Fail("配置校验失败:" + err.Error())
}
// 保存之前删除多于的配置信息
for _, ref := range authConfig.PolicyRefs {
ref.AuthPolicy = nil
}
configJSON, err := json.Marshal(authConfig)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().HTTPWebRPC().UpdateHTTPWebAuth(this.AdminContext(), &pb.UpdateHTTPWebAuthRequest{
WebId: params.WebId,
AuthJSON: configJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -13,7 +13,9 @@ func init() {
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeServer)).
Helper(serverutils.NewServerHelper()).
Prefix("/servers/server/settings/access").
Get("", new(IndexAction)).
GetPost("", new(IndexAction)).
GetPost("/createPopup", new(CreatePopupAction)).
GetPost("/updatePopup", new(UpdatePopupAction)).
EndAll()
})
}

View File

@@ -0,0 +1,167 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package access
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
)
type UpdatePopupAction struct {
actionutils.ParentAction
}
func (this *UpdatePopupAction) Init() {
this.Nav("", "", "")
}
func (this *UpdatePopupAction) RunGet(params struct {
PolicyId int64
}) {
this.Data["authTypes"] = serverconfigs.FindAllHTTPAuthTypes()
policyResp, err := this.RPC().HTTPAuthPolicyRPC().FindEnabledHTTPAuthPolicy(this.AdminContext(), &pb.FindEnabledHTTPAuthPolicyRequest{HttpAuthPolicyId: params.PolicyId})
if err != nil {
this.ErrorPage(err)
return
}
policy := policyResp.HttpAuthPolicy
if policy == nil {
this.NotFound("httpAuthPolicy", params.PolicyId)
return
}
var authParams = map[string]interface{}{}
if len(policy.ParamsJSON) > 0 {
err = json.Unmarshal(policy.ParamsJSON, &authParams)
if err != nil {
this.ErrorPage(err)
return
}
}
this.Data["policy"] = maps.Map{
"id": policy.Id,
"isOn": policy.IsOn,
"name": policy.Name,
"type": policy.Type,
"params": authParams,
}
this.Show()
}
func (this *UpdatePopupAction) RunPost(params struct {
PolicyId int64
Name string
IsOn bool
// BasicAuth
HttpAuthBasicAuthUsersJSON []byte
BasicAuthRealm string
BasicAuthCharset string
// SubRequest
SubRequestURL string
SubRequestMethod string
SubRequestFollowRequest bool
Must *actions.Must
CSRF *actionutils.CSRF
}) {
defer this.CreateLogInfo("修改HTTP认证 %d", params.PolicyId)
policyResp, err := this.RPC().HTTPAuthPolicyRPC().FindEnabledHTTPAuthPolicy(this.AdminContext(), &pb.FindEnabledHTTPAuthPolicyRequest{HttpAuthPolicyId: params.PolicyId})
if err != nil {
this.ErrorPage(err)
return
}
policy := policyResp.HttpAuthPolicy
if policy == nil {
this.NotFound("httpAuthPolicy", params.PolicyId)
return
}
policyType := policy.Type
params.Must.
Field("name", params.Name).
Require("请输入名称")
var ref = &serverconfigs.HTTPAuthPolicyRef{IsOn: true}
var paramsJSON []byte
switch policyType {
case serverconfigs.HTTPAuthTypeBasicAuth:
users := []*serverconfigs.HTTPAuthBasicMethodUser{}
err := json.Unmarshal(params.HttpAuthBasicAuthUsersJSON, &users)
if err != nil {
this.ErrorPage(err)
return
}
if len(users) == 0 {
this.Fail("请添加至少一个用户")
}
method := &serverconfigs.HTTPAuthBasicMethod{
Users: users,
Realm: params.BasicAuthRealm,
Charset: params.BasicAuthCharset,
}
methodJSON, err := json.Marshal(method)
if err != nil {
this.ErrorPage(err)
return
}
paramsJSON = methodJSON
case serverconfigs.HTTPAuthTypeSubRequest:
params.Must.Field("subRequestURL", params.SubRequestURL).
Require("请输入子请求URL")
if params.SubRequestFollowRequest {
params.SubRequestMethod = ""
}
method := &serverconfigs.HTTPAuthSubRequestMethod{
URL: params.SubRequestURL,
Method: params.SubRequestMethod,
}
methodJSON, err := json.Marshal(method)
if err != nil {
this.ErrorPage(err)
return
}
paramsJSON = methodJSON
default:
this.Fail("不支持的认证类型'" + policyType + "'")
}
var paramsMap map[string]interface{}
err = json.Unmarshal(paramsJSON, &paramsMap)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().HTTPAuthPolicyRPC().UpdateHTTPAuthPolicy(this.AdminContext(), &pb.UpdateHTTPAuthPolicyRequest{
HttpAuthPolicyId: params.PolicyId,
Name: params.Name,
ParamsJSON: paramsJSON,
IsOn: params.IsOn,
})
if err != nil {
this.ErrorPage(err)
return
}
ref.AuthPolicy = &serverconfigs.HTTPAuthPolicy{
Id: params.PolicyId,
Name: params.Name,
IsOn: params.IsOn,
Type: policyType,
Params: paramsMap,
}
this.Data["policyRef"] = ref
this.Success()
}

View File

@@ -1,7 +1,12 @@
package access
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/actions"
)
type IndexAction struct {
@@ -9,12 +14,63 @@ type IndexAction struct {
}
func (this *IndexAction) Init() {
this.Nav("", "setting", "index")
this.SecondMenu("access")
}
func (this *IndexAction) RunGet(params struct {
ServerId int64
LocationId int64
}) {
// TODO
webConfig, err := dao.SharedHTTPWebDAO.FindWebConfigWithLocationId(this.AdminContext(), params.LocationId)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["webId"] = webConfig.Id
this.Data["authConfig"] = webConfig.Auth
this.Show()
}
func (this *IndexAction) RunPost(params struct {
WebId int64
AuthJSON []byte
Must *actions.Must
CSRF *actionutils.CSRF
}) {
defer this.CreateLogInfo("修改Web %d 的认证设置", params.WebId)
var authConfig = &serverconfigs.HTTPAuthConfig{}
err := json.Unmarshal(params.AuthJSON, authConfig)
if err != nil {
this.ErrorPage(err)
return
}
err = authConfig.Init()
if err != nil {
this.Fail("配置校验失败:" + err.Error())
}
// 保存之前删除多于的配置信息
for _, ref := range authConfig.PolicyRefs {
ref.AuthPolicy = nil
}
configJSON, err := json.Marshal(authConfig)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().HTTPWebRPC().UpdateHTTPWebAuth(this.AdminContext(), &pb.UpdateHTTPWebAuthRequest{
WebId: params.WebId,
AuthJSON: configJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -16,7 +16,7 @@ func init() {
Helper(serverutils.NewServerHelper()).
Data("tinyMenuItem", "access").
Prefix("/servers/server/settings/locations/access").
Get("", new(IndexAction)).
GetPost("", new(IndexAction)).
EndAll()
})
}

View File

@@ -100,12 +100,13 @@ func (this *LocationHelper) createMenus(serverIdString string, locationIdString
"name": "缓存",
"url": "/servers/server/settings/locations/cache?serverId=" + serverIdString + "&locationId=" + locationIdString,
"isActive": secondMenuItem == "cache",
"isOn": locationConfig != nil && locationConfig.Web != nil && locationConfig.Web.Cache != nil && locationConfig.Web.Cache.IsOn && len(locationConfig.Web.Cache.CacheRefs) > 0,
"isOn": locationConfig != nil && locationConfig.Web != nil && locationConfig.Web.Cache != nil && locationConfig.Web.Cache.IsPrior && locationConfig.Web.Cache.IsOn && len(locationConfig.Web.Cache.CacheRefs) > 0,
})
menuItems = append(menuItems, maps.Map{
"name": "访问控制",
"url": "/servers/server/settings/locations/access?serverId=" + serverIdString + "&locationId=" + locationIdString,
"isActive": secondMenuItem == "access",
"isOn": locationConfig != nil && locationConfig.Web != nil && locationConfig.Web.Auth != nil && locationConfig.Web.Auth.IsPrior,
})
menuItems = append(menuItems, maps.Map{
"name": "字符编码",

View File

@@ -275,6 +275,7 @@ func (this *ServerHelper) createSettingsMenu(secondMenuItem string, serverIdStri
"name": "访问控制",
"url": "/servers/server/settings/access?serverId=" + serverIdString,
"isActive": secondMenuItem == "access",
"isOn": serverConfig.Web != nil && serverConfig.Web.Auth != nil && serverConfig.Web.Auth.IsOn,
})
menuItems = append(menuItems, maps.Map{
"name": "字符编码",

View File

@@ -191,7 +191,7 @@ func (this *InstallAction) RunPost(params struct {
Username: adminMap.GetString("username"),
Password: adminMap.GetString("password"),
})
// 这里我们尝试多次是为了当代API节点启动完毕
// 这里我们尝试多次是为了等待API节点启动完毕
if err != nil {
time.Sleep(1 * time.Second)
}

View File

@@ -36,15 +36,24 @@ func (this *UpdateAction) RunGet(params struct {
return
}
// AccessKey数量
countAccessKeyResp, err := this.RPC().UserAccessKeyRPC().CountAllEnabledUserAccessKeys(this.AdminContext(), &pb.CountAllEnabledUserAccessKeysRequest{UserId: params.UserId})
if err != nil {
this.ErrorPage(err)
return
}
countAccessKeys := countAccessKeyResp.Count
this.Data["user"] = maps.Map{
"id": user.Id,
"username": user.Username,
"fullname": user.Fullname,
"email": user.Email,
"tel": user.Tel,
"remark": user.Remark,
"mobile": user.Mobile,
"isOn": user.IsOn,
"id": user.Id,
"username": user.Username,
"fullname": user.Fullname,
"email": user.Email,
"tel": user.Tel,
"remark": user.Remark,
"mobile": user.Mobile,
"isOn": user.IsOn,
"countAccessKeys": countAccessKeys,
}
this.Data["clusterId"] = 0

View File

@@ -43,16 +43,25 @@ func (this *UserAction) RunGet(params struct {
}
}
// AccessKey数量
countAccessKeyResp, err := this.RPC().UserAccessKeyRPC().CountAllEnabledUserAccessKeys(this.AdminContext(), &pb.CountAllEnabledUserAccessKeysRequest{UserId: params.UserId})
if err != nil {
this.ErrorPage(err)
return
}
countAccessKeys := countAccessKeyResp.Count
this.Data["user"] = maps.Map{
"id": user.Id,
"username": user.Username,
"fullname": user.Fullname,
"email": user.Email,
"tel": user.Tel,
"remark": user.Remark,
"mobile": user.Mobile,
"isOn": user.IsOn,
"cluster": clusterMap,
"id": user.Id,
"username": user.Username,
"fullname": user.Fullname,
"email": user.Email,
"tel": user.Tel,
"remark": user.Remark,
"mobile": user.Mobile,
"isOn": user.IsOn,
"cluster": clusterMap,
"countAccessKeys": countAccessKeys,
}
this.Show()

View File

@@ -7,7 +7,7 @@ import (
"github.com/iwind/TeaGo/maps"
)
// 查找用户基本信息
// InitUser 查找用户基本信息
func InitUser(p *actionutils.ParentAction, userId int64) error {
resp, err := p.RPC().UserRPC().FindEnabledUser(p.AdminContext(), &pb.FindEnabledUserRequest{UserId: userId})
if err != nil {
@@ -16,10 +16,21 @@ func InitUser(p *actionutils.ParentAction, userId int64) error {
if resp.User == nil {
return errors.New("not found user")
}
// AccessKey数量
countAccessKeysResp, err := p.RPC().UserAccessKeyRPC().CountAllEnabledUserAccessKeys(p.AdminContext(), &pb.CountAllEnabledUserAccessKeysRequest{
AdminId: 0,
UserId: userId,
})
if err != nil {
return err
}
p.Data["user"] = maps.Map{
"id": userId,
"fullname": resp.User.Fullname,
"username": resp.User.Username,
"id": userId,
"fullname": resp.User.Fullname,
"username": resp.User.Username,
"countAccessKeys": countAccessKeysResp.Count,
}
return nil
}

View File

@@ -0,0 +1,101 @@
// 基本认证用户配置
Vue.component("http-auth-basic-auth-user-box", {
props: ["v-users"],
data: function () {
let users = this.vUsers
if (users == null) {
users = []
}
return {
users: users,
isAdding: false,
updatingIndex: -1,
username: "",
password: ""
}
},
methods: {
add: function () {
this.isAdding = true
this.username = ""
this.password = ""
let that = this
setTimeout(function () {
that.$refs.username.focus()
}, 100)
},
cancel: function () {
this.isAdding = false
this.updatingIndex = -1
},
confirm: function () {
let that = this
if (this.username.length == 0) {
teaweb.warn("请输入用户名", function () {
that.$refs.username.focus()
})
return
}
if (this.password.length == 0) {
teaweb.warn("请输入密码", function () {
that.$refs.password.focus()
})
return
}
if (this.updatingIndex < 0) {
this.users.push({
username: this.username,
password: this.password
})
} else {
this.users[this.updatingIndex].username = this.username
this.users[this.updatingIndex].password = this.password
}
this.cancel()
},
update: function (index, user) {
this.updatingIndex = index
this.isAdding = true
this.username = user.username
this.password = user.password
let that = this
setTimeout(function () {
that.$refs.username.focus()
}, 100)
},
remove: function (index) {
this.users.$remove(index)
}
},
template: `<div>
<input type="hidden" name="httpAuthBasicAuthUsersJSON" :value="JSON.stringify(users)"/>
<div v-if="users.length > 0">
<div class="ui label small basic" v-for="(user, index) in users">
{{user.username}} <a href="" title="修改" @click.prevent="update(index, user)"><i class="icon pencil tiny"></i></a>
<a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove small"></i></a>
</div>
<div class="ui divider"></div>
</div>
<div v-show="isAdding">
<div class="ui fields inline">
<div class="ui field">
<input type="text" placeholder="用户名" v-model="username" size="15" ref="username"/>
</div>
<div class="ui field">
<input type="password" placeholder="密码" v-model="password" size="15" ref="password"/>
</div>
<div class="ui field">
<button class="ui button tiny" type="button" @click.prevent="confirm">确定</button>&nbsp;
<a href="" title="取消" @click.prevent="cancel"><i class="icon remove small"></i></a>
</div>
</div>
</div>
<div v-if="!isAdding" style="margin-top: 1em">
<button class="ui button tiny" type="button" @click.prevent="add">+</button>
</div>
</div>`
})

View File

@@ -0,0 +1,113 @@
// 认证设置
Vue.component("http-auth-config-box", {
props: ["v-auth-config", "v-is-location"],
data: function () {
let authConfig = this.vAuthConfig
if (authConfig == null) {
authConfig = {
isPrior: false,
isOn: false
}
}
if (authConfig.policyRefs == null) {
authConfig.policyRefs = []
}
return {
authConfig: authConfig
}
},
methods: {
isOn: function () {
return (!this.vIsLocation || this.authConfig.isPrior) && this.authConfig.isOn
},
add: function () {
let that = this
teaweb.popup("/servers/server/settings/access/createPopup", {
callback: function (resp) {
that.authConfig.policyRefs.push(resp.data.policyRef)
},
height: "28em"
})
},
update: function (index, policyId) {
let that = this
teaweb.popup("/servers/server/settings/access/updatePopup?policyId=" + policyId, {
callback: function (resp) {
teaweb.success("保存成功", function () {
teaweb.reload()
})
},
height: "28em"
})
},
remove: function (index) {
this.authConfig.policyRefs.$remove(index)
},
methodName: function (methodType) {
switch (methodType) {
case "basicAuth":
return "BasicAuth"
case "subRequest":
return "子请求"
}
return ""
}
},
template: `<div>
<input type="hidden" name="authJSON" :value="JSON.stringify(authConfig)"/>
<table class="ui table selectable definition">
<prior-checkbox :v-config="authConfig" v-if="vIsLocation"></prior-checkbox>
<tbody v-show="!vIsLocation || authConfig.isPrior">
<tr>
<td class="title">启用认证</td>
<td>
<div class="ui checkbox">
<input type="checkbox" v-model="authConfig.isOn"/>
<label></label>
</div>
</td>
</tr>
</tbody>
</table>
<div class="margin"></div>
<!-- 认证方式 -->
<div v-show="isOn()">
<h4>认证方式</h4>
<table class="ui table selectable celled" v-show="authConfig.policyRefs.length > 0">
<thead>
<tr>
<th class="three wide">名称</th>
<th class="three wide">认证方法</th>
<th>参数</th>
<th class="two wide">状态</th>
<th class="two op">操作</th>
</tr>
</thead>
<tbody v-for="(ref, index) in authConfig.policyRefs" :key="ref.authPolicyId">
<tr>
<td>{{ref.authPolicy.name}}</td>
<td>
{{methodName(ref.authPolicy.type)}}
</td>
<td>
<span v-if="ref.authPolicy.type == 'basicAuth'">{{ref.authPolicy.params.users.length}}个用户</span>
<span v-if="ref.authPolicy.type == 'subRequest'">
<span v-if="ref.authPolicy.params.method.length > 0" class="grey">[{{ref.authPolicy.params.method}}]</span>
{{ref.authPolicy.params.url}}
</span>
</td>
<td>
<label-on :v-is-on="ref.authPolicy.isOn"></label-on>
</td>
<td>
<a href="" @click.prevent="update(index, ref.authPolicyId)">修改</a> &nbsp;
<a href="" @click.prevent="remove(index)">删除</a>
</td>
</tr>
</tbody>
</table>
<button class="ui button small" type="button" @click.prevent="add">+添加认证方式</button>
</div>
<div class="margin"></div>
</div>`
})

View File

@@ -3,4 +3,5 @@
<span class="item">|</span>
<menu-item :href="'/admins/admin?adminId=' + admin.id" code="index">"{{admin.fullname}}" 详情</menu-item>
<menu-item :href="'/admins/update?adminId=' + admin.id" code="update">修改</menu-item>
<menu-item :href="'/admins/accessKeys?adminId=' + admin.id" code="accessKey">API AccessKey({{admin.countAccessKeys}})</menu-item>
</first-menu>

View File

@@ -0,0 +1,28 @@
{$layout "layout_popup"}
<h3>创建新AccessKey</h3>
<form class="ui form" method="post" data-tea-action="$" data-tea-success="success">
<csrf-token></csrf-token>
<input type="hidden" name="adminId" :value="adminId"/>
<table class="ui table definition selectable">
<tr>
<td class="title">AccessKey ID</td>
<td><span class="disabled">自动生成</span></td>
</tr>
<tr>
<td>AccessKey密钥</td>
<td><span class="disabled">自动生成</span></td>
</tr>
<tr>
<td class="title">备注 *</td>
<td>
<textarea rows="2" name="description" maxlength="100" ref="focus"></textarea>
<p class="comment">描述AccessKey的用途等。</p>
</td>
</tr>
</table>
<submit-btn></submit-btn>
</form>

View File

@@ -0,0 +1,39 @@
{$layout}
{$template "../admin_menu"}
<second-menu>
<menu-item @click.prevent="createAccessKey()">[创建AccessKey]</menu-item>
</second-menu>
<p class="comment" v-if="accessKeys.length == 0">暂时还没有AccessKey。</p>
<table class="ui table selectable" v-if="accessKeys.length > 0">
<thead>
<tr>
<th>AccessKey ID</th>
<th>AccessKey密钥</th>
<th>备注</th>
<th>最后访问</th>
<th>状态</th>
<th class="two op">操作</th>
</tr>
</thead>
<tr v-for="accessKey in accessKeys">
<td :class="{disabled: !accessKey.isOn}">{{accessKey.uniqueId}}</td>
<td :class="{disabled: !accessKey.isOn}">{{accessKey.secret}}</td>
<td :class="{disabled: !accessKey.isOn}">{{accessKey.description}}</td>
<td :class="{disabled: !accessKey.isOn}">
<span v-if="accessKey.accessedTime.length > 0">{{accessKey.accessedTime}}</span>
<span v-else class="disabled">尚无访问</span>
</td>
<td>
<span v-if="accessKey.isOn" class="green">已启用</span>
<span v-else class="disabled">已禁用</span>
</td>
<td>
<a href="" v-if="accessKey.isOn" @click.prevent="updateAccessKeyIsOn(accessKey.id, false)">禁用</a>
<a href="" v-if="!accessKey.isOn" @click.prevent="updateAccessKeyIsOn(accessKey.id, true)">启用</a>
&nbsp; <a href="" @click.prevent="deleteAccessKey(accessKey.id)">删除</a>
</td>
</tr>
</table>

View File

@@ -0,0 +1,41 @@
Tea.context(function () {
this.createAccessKey = function () {
teaweb.popup("/admins/accessKeys/createPopup?adminId=" + this.admin.id, {
callback: function () {
teaweb.success("保存成功", function () {
teaweb.reload()
})
}
})
}
this.updateAccessKeyIsOn = function (accessKeyId, isOn) {
let that = this
let message = ""
if (isOn) {
message = "确定要启用此AccessKey吗"
} else {
message = "确定要禁用此AccessKey吗"
}
teaweb.confirm(message, function () {
that.$post(".updateIsOn")
.params({
accessKeyId: accessKeyId,
isOn: isOn ? 1 : 0
})
.refresh()
})
}
this.deleteAccessKey = function (accessKeyId) {
let that = this
teaweb.confirm("确定要删除此AccessKey吗", function () {
that.$post(".delete")
.params({
accessKeyId: accessKeyId
})
.refresh()
})
}
})

View File

@@ -1,10 +1,13 @@
{$layout}
{$template "../waf_menu"}
{$template "menu"}
{$template "../waf_menu"}
{$template "menu"}
<second-menu style="margin-top: -1em">
<span class="item">ID: {{listId}} &nbsp; <tip-icon content="ID可以用于使用API操作此IP名单"></tip-icon></span>
</second-menu>
<p class="comment" v-if="items.length == 0">暂时还没有IP。</p>
<p class="comment" v-if="items.length == 0">暂时还没有IP。</p>
<ip-list-table v-if="items.length > 0" :v-items="items" @update-item="updateItem" @delete-item="deleteItem"></ip-list-table>
<ip-list-table v-if="items.length > 0" :v-items="items" @update-item="updateItem" @delete-item="deleteItem"></ip-list-table>
<div class="page" v-html="page"></div>
<div class="page" v-html="page"></div>

View File

@@ -0,0 +1,82 @@
{$layout "layout_popup"}
<h3>创建认证方式</h3>
<form class="ui form" data-tea-action="$" data-tea-success="success">
<csrf-token></csrf-token>
<table class="ui table definition selectable">
<tr>
<td class="title">名称 *</td>
<td>
<input type="text" name="name" maxlength="50" ref="focus"/>
</td>
</tr>
<tr>
<td>认证类型 *</td>
<td>
<select class="ui dropdown auto-width" name="type" v-model="type" @change="changeType">
<option value="">[认证类型]</option>
<option v-for="authType in authTypes" :value="authType.code">{{authType.name}}</option>
</select>
<p class="comment" v-html="authDescription"></p>
</td>
</tr>
<!-- BasicAuth -->
<tbody v-show="type == 'basicAuth'">
<tr>
<td>用户 *</td>
<td>
<http-auth-basic-auth-user-box></http-auth-basic-auth-user-box>
</td>
</tr>
<tr>
<td colspan="2">
<a href="" @click.prevent="showMoreBasicAuthOptions()">更多选项<i class="ui icon angle" :class="{up: moreBasicAuthOptionsVisible, down: !moreBasicAuthOptionsVisible}"></i></a>
</td>
</tr>
<tr v-show="moreBasicAuthOptionsVisible">
<td>认证领域名<em>Realm</em></td>
<td>
<input type="text" name="basicAuthRealm" value="" maxlength="100"/>
</td>
</tr>
<tr v-show="moreBasicAuthOptionsVisible">
<td>字符集</td>
<td>
<input type="text" name="basicAuthCharset" style="width: 6em" maxlength="50"/>
<p class="comment">类似于<code-label>UTF-8</code-label></p>
</td>
</tr>
</tbody>
<!-- SubRequest -->
<tbody v-show="type == 'subRequest'">
<tr>
<td>子请求URL *</td>
<td>
<input type="text" name="subRequestURL" maxlength="1024"/>
<p class="comment">可以是一个完整的URL也可以是一个路径。</p>
</td>
</tr>
<tr>
<td>请求方法</td>
<td>
<radio name="subRequestFollowRequest" :v-value="1" v-model="subRequestFollowRequest">同当前请求一致</radio> &nbsp; &nbsp;
<radio name="subRequestFollowRequest" :v-value="0" v-model="subRequestFollowRequest">自定义</radio>
<div style="margin-top: 0.8em" v-show="subRequestFollowRequest == 0">
<div class="ui divider"></div>
<select class="ui dropdown auto-width" name="subRequestMethod">
<option value="POST">POST</option>
<option value="GET">GET</option>
<option value="PUT">PUT</option>
<option value="HEAD">HEAD</option>
</select>
</div>
</td>
</tr>
</tbody>
</table>
<submit-btn></submit-btn>
</form>

View File

@@ -0,0 +1,32 @@
Tea.context(function () {
this.success = NotifyPopup
this.type = ""
this.authDescription = ""
this.changeType = function () {
let that = this
let authType = this.authTypes.$find(function (k, v) {
return v.code == that.type
})
if (authType != null) {
this.authDescription = authType.description
} else {
this.authDescription = ""
}
}
/**
* 基本认证
*/
this.moreBasicAuthOptionsVisible = false
this.showMoreBasicAuthOptions = function () {
this.moreBasicAuthOptionsVisible = !this.moreBasicAuthOptionsVisible
}
/**
* 子请求
*/
this.subRequestFollowRequest = 1
})

View File

@@ -3,5 +3,10 @@
{$template "/left_menu"}
<div class="right-box">
<p class="ui message">此功能暂未开放,敬请期待。</p>
<form class="ui form" data-tea-action="$" data-tea-success="success">
<csrf-token></csrf-token>
<input type="hidden" name="webId" :value="webId">
<http-auth-config-box :v-auth-config="authConfig"></http-auth-config-box>
<submit-btn></submit-btn>
</form>
</div>

View File

@@ -0,0 +1,3 @@
Tea.context(function () {
this.success = NotifyReloadSuccess("保存成功")
})

View File

@@ -0,0 +1,85 @@
{$layout "layout_popup"}
<h3>修改认证方式</h3>
<form class="ui form" data-tea-action="$" data-tea-success="success">
<csrf-token></csrf-token>
<input type="hidden" name="policyId" :value="policy.id"/>
<table class="ui table definition selectable">
<tr>
<td class="title">名称 *</td>
<td>
<input type="text" name="name" maxlength="50" ref="focus" v-model="policy.name"/>
</td>
</tr>
<tr>
<td>认证类型 *</td>
<td>
{{policy.typeName}}
<p class="comment" v-html="authDescription"></p>
</td>
</tr>
<!-- BasicAuth -->
<tbody v-show="type == 'basicAuth'">
<tr>
<td>用户 *</td>
<td>
<http-auth-basic-auth-user-box :v-users="policy.params.users"></http-auth-basic-auth-user-box>
</td>
</tr>
<tr>
<td colspan="2">
<a href="" @click.prevent="showMoreBasicAuthOptions()">更多选项<i class="ui icon angle" :class="{up: moreBasicAuthOptionsVisible, down: !moreBasicAuthOptionsVisible}"></i></a>
</td>
</tr>
<tr v-show="moreBasicAuthOptionsVisible">
<td>认证领域名<em>Realm</em></td>
<td>
<input type="text" name="basicAuthRealm" value="" maxlength="100" v-model="policy.params.realm"/>
</td>
</tr>
<tr v-show="moreBasicAuthOptionsVisible">
<td>字符集</td>
<td>
<input type="text" name="basicAuthCharset" style="width: 6em" v-model="policy.params.charset" maxlength="50"/>
<p class="comment">类似于<code-label>utf-8</code-label></p>
</td>
</tr>
</tbody>
<!-- SubRequest -->
<tbody v-show="type == 'subRequest'">
<tr>
<td>子请求URL *</td>
<td>
<input type="text" name="subRequestURL" maxlength="1024" v-model="policy.params.url"/>
<p class="comment">可以是一个完整的URL也可以是一个路径。</p>
</td>
</tr>
<tr>
<td>请求方法</td>
<td>
<radio name="subRequestFollowRequest" :v-value="1" v-model="subRequestFollowRequest">同当前请求一致</radio> &nbsp; &nbsp;
<radio name="subRequestFollowRequest" :v-value="0" v-model="subRequestFollowRequest">自定义</radio>
<div style="margin-top: 0.8em" v-show="subRequestFollowRequest == 0">
<div class="ui divider"></div>
<select class="ui dropdown auto-width" name="subRequestMethod" v-model="policy.params.method">
<option value="">[请选择]</option>
<option value="POST">POST</option>
<option value="GET">GET</option>
<option value="PUT">PUT</option>
<option value="HEAD">HEAD</option>
</select>
</div>
</td>
</tr>
</tbody>
<tr>
<td>是否启用</td>
<td><checkbox name="isOn" value="1" v-model="policy.isOn"></checkbox></td>
</tr>
</table>
<submit-btn></submit-btn>
</form>

View File

@@ -0,0 +1,37 @@
Tea.context(function () {
this.success = NotifyPopup
this.type = this.policy.type
this.authDescription = ""
this.$delay(function () {
this.changeType()
})
this.changeType = function () {
let that = this
let authType = this.authTypes.$find(function (k, v) {
return v.code == that.type
})
if (authType != null) {
this.policy.typeName = authType.name
this.authDescription = authType.description
} else {
this.authDescription = ""
}
}
/**
* 基本认证
*/
this.moreBasicAuthOptionsVisible = false
this.showMoreBasicAuthOptions = function () {
this.moreBasicAuthOptionsVisible = !this.moreBasicAuthOptionsVisible
}
/**
* 子请求
*/
this.subRequestFollowRequest = (this.policy.params.method != null && this.policy.params.method.length > 0) ? 0 : 1
})

View File

@@ -1,13 +1,16 @@
{$layout}
{$template "/left_menu"}
<div class="right-box">
{$template "../location_menu"}
{$template "../left_menu"}
{$template "../location_menu"}
{$template "../left_menu"}
<div class="right-box tiny">
<div class="margin"></div>
<p class="ui message">此功能暂未开放,敬请期待。</p>
</div>
<div class="right-box tiny">
<form class="ui form" data-tea-action="$" data-tea-success="success">
<csrf-token></csrf-token>
<input type="hidden" name="webId" :value="webId">
<http-auth-config-box :v-auth-config="authConfig" :v-is-location="true"></http-auth-config-box>
<submit-btn></submit-btn>
</form>
</div>
</div>

View File

@@ -0,0 +1,3 @@
Tea.context(function () {
this.success = NotifyReloadSuccess("保存成功")
})

View File

@@ -4,5 +4,5 @@
<menu-item :href="'/users/user?userId=' + user.id" code="index">{{user.fullname}}&nbsp; <span class="small">({{user.username}})</span></menu-item>
<menu-item :href="'/users/update?userId=' + user.id" code="update">修改</menu-item>
<menu-item :href="'/users/features?userId=' + user.id" code="feature">功能</menu-item>
<menu-item :href="'/users/accessKeys?userId=' + user.id" code="accessKey">API AccessKey</menu-item>
<menu-item :href="'/users/accessKeys?userId=' + user.id" code="accessKey">API AccessKey({{user.countAccessKeys}})</menu-item>
</first-menu>

View File

@@ -7,6 +7,14 @@
<input type="hidden" name="userId" :value="userId"/>
<table class="ui table definition selectable">
<tr>
<td class="title">AccessKey ID</td>
<td><span class="disabled">自动生成</span></td>
</tr>
<tr>
<td>AccessKey密钥</td>
<td><span class="disabled">自动生成</span></td>
</tr>
<tr>
<td class="title">备注 *</td>
<td>