mirror of
https://gitee.com/IrisVega/frp.git
synced 2024-11-01 22:31:29 +08:00
web: support http basic auth in dashboard
This commit is contained in:
parent
fd268b5082
commit
3f17837a2c
6
Makefile
6
Makefile
@ -7,9 +7,11 @@ build: frps frpc
|
|||||||
|
|
||||||
# compile assets into binary file
|
# compile assets into binary file
|
||||||
file:
|
file:
|
||||||
|
rm -rf ./assets/static/*
|
||||||
|
cp -rf ./web/frps/dist/* ./assets/static
|
||||||
go get -d github.com/rakyll/statik
|
go get -d github.com/rakyll/statik
|
||||||
@go install github.com/rakyll/statik
|
go install github.com/rakyll/statik
|
||||||
@rm -rf ./assets/statik
|
rm -rf ./assets/statik
|
||||||
go generate ./assets/...
|
go generate ./assets/...
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
|
@ -1 +1 @@
|
|||||||
<!DOCTYPE html> <html lang=en> <head> <meta charset=utf-8> <title>frps dashboard</title> <link rel="shortcut icon" href="favicon.ico"></head> <body> <div id=app></div> <script type="text/javascript" src="manifest.js?b99c1346247a42f912f8"></script><script type="text/javascript" src="vendor.js?66dfcf2d1c500e900413"></script><script type="text/javascript" src="index.js?ba80138d6369555bbd4e"></script></body> </html>
|
<!DOCTYPE html> <html lang=en> <head> <meta charset=utf-8> <title>frps dashboard</title> <link rel="shortcut icon" href="favicon.ico"></head> <body> <div id=app></div> <script type="text/javascript" src="manifest.js?b52826060da73c6b5a10"></script><script type="text/javascript" src="vendor.js?66dfcf2d1c500e900413"></script><script type="text/javascript" src="index.js?ceb589f1be7a87112dbd"></script></body> </html>
|
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
|||||||
!function(e){function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}var n=window.webpackJsonp;window.webpackJsonp=function(t,c,u){for(var i,a,f,l=0,s=[];l<t.length;l++)a=t[l],o[a]&&s.push(o[a][0]),o[a]=0;for(i in c)Object.prototype.hasOwnProperty.call(c,i)&&(e[i]=c[i]);for(n&&n(t,c,u);s.length;)s.shift()();if(u)for(l=0;l<u.length;l++)f=r(r.s=u[l]);return f};var t={},o={2:0};r.e=function(e){function n(){u.onerror=u.onload=null,clearTimeout(i);var r=o[e];0!==r&&(r&&r[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}if(0===o[e])return Promise.resolve();if(o[e])return o[e][2];var t=new Promise(function(r,n){o[e]=[r,n]});o[e][2]=t;var c=document.getElementsByTagName("head")[0],u=document.createElement("script");u.type="text/javascript",u.charset="utf-8",u.async=!0,u.timeout=12e4,r.nc&&u.setAttribute("nonce",r.nc),u.src=r.p+""+e+".js?"+{0:"ba80138d6369555bbd4e",1:"66dfcf2d1c500e900413"}[e];var i=setTimeout(n,12e4);return u.onerror=u.onload=n,c.appendChild(u),t},r.m=e,r.c=t,r.i=function(e){return e},r.d=function(e,n,t){r.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:t})},r.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(n,"a",n),n},r.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},r.p="",r.oe=function(e){throw console.error(e),e}}([]);
|
!function(e){function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}var n=window.webpackJsonp;window.webpackJsonp=function(t,c,u){for(var i,a,f,l=0,s=[];l<t.length;l++)a=t[l],o[a]&&s.push(o[a][0]),o[a]=0;for(i in c)Object.prototype.hasOwnProperty.call(c,i)&&(e[i]=c[i]);for(n&&n(t,c,u);s.length;)s.shift()();if(u)for(l=0;l<u.length;l++)f=r(r.s=u[l]);return f};var t={},o={2:0};r.e=function(e){function n(){u.onerror=u.onload=null,clearTimeout(i);var r=o[e];0!==r&&(r&&r[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}if(0===o[e])return Promise.resolve();if(o[e])return o[e][2];var t=new Promise(function(r,n){o[e]=[r,n]});o[e][2]=t;var c=document.getElementsByTagName("head")[0],u=document.createElement("script");u.type="text/javascript",u.charset="utf-8",u.async=!0,u.timeout=12e4,r.nc&&u.setAttribute("nonce",r.nc),u.src=r.p+""+e+".js?"+{0:"ceb589f1be7a87112dbd",1:"66dfcf2d1c500e900413"}[e];var i=setTimeout(n,12e4);return u.onerror=u.onload=n,c.appendChild(u),t},r.m=e,r.c=t,r.i=function(e){return e},r.d=function(e,n,t){r.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:t})},r.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(n,"a",n),n},r.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},r.p="",r.oe=function(e){throw console.error(e),e}}([]);
|
File diff suppressed because one or more lines are too long
@ -36,20 +36,19 @@ func RunDashboardServer(addr string, port int64) (err error) {
|
|||||||
router := httprouter.New()
|
router := httprouter.New()
|
||||||
|
|
||||||
// api, see dashboard_api.go
|
// api, see dashboard_api.go
|
||||||
//mux.HandleFunc("/api/reload", use(apiReload, basicAuth))
|
router.GET("/api/serverinfo", httprouterBasicAuth(apiServerInfo))
|
||||||
router.GET("/api/serverinfo", apiServerInfo)
|
router.GET("/api/proxy/tcp", httprouterBasicAuth(apiProxyTcp))
|
||||||
router.GET("/api/proxy/tcp", apiProxyTcp)
|
router.GET("/api/proxy/udp", httprouterBasicAuth(apiProxyUdp))
|
||||||
router.GET("/api/proxy/udp", apiProxyUdp)
|
router.GET("/api/proxy/http", httprouterBasicAuth(apiProxyHttp))
|
||||||
router.GET("/api/proxy/http", apiProxyHttp)
|
router.GET("/api/proxy/https", httprouterBasicAuth(apiProxyHttps))
|
||||||
router.GET("/api/proxy/https", apiProxyHttps)
|
router.GET("/api/proxy/traffic/:name", httprouterBasicAuth(apiProxyTraffic))
|
||||||
router.GET("/api/proxy/traffic/:name", apiProxyTraffic)
|
|
||||||
|
|
||||||
// view
|
// view
|
||||||
router.Handler("GET", "/favicon.ico", http.FileServer(assets.FileSystem))
|
router.Handler("GET", "/favicon.ico", http.FileServer(assets.FileSystem))
|
||||||
router.Handler("GET", "/static/*filepath", http.StripPrefix("/static/", http.FileServer(assets.FileSystem)))
|
router.Handler("GET", "/static/*filepath", basicAuthWraper(http.StripPrefix("/static/", http.FileServer(assets.FileSystem))))
|
||||||
router.HandlerFunc("GET", "/", func(w http.ResponseWriter, r *http.Request) {
|
router.HandlerFunc("GET", "/", basicAuth(func(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Redirect(w, r, "/static/", http.StatusMovedPermanently)
|
http.Redirect(w, r, "/static/", http.StatusMovedPermanently)
|
||||||
})
|
}))
|
||||||
|
|
||||||
address := fmt.Sprintf("%s:%d", addr, port)
|
address := fmt.Sprintf("%s:%d", addr, port)
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
@ -77,22 +76,50 @@ func use(h http.HandlerFunc, middleware ...func(http.HandlerFunc) http.HandlerFu
|
|||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
func basicAuth(h http.HandlerFunc) http.HandlerFunc {
|
type AuthWraper struct {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
h http.Handler
|
||||||
|
user string
|
||||||
|
passwd string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (aw *AuthWraper) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
user, passwd, hasAuth := r.BasicAuth()
|
||||||
|
if hasAuth && user == aw.user || passwd == aw.passwd {
|
||||||
|
aw.h.ServeHTTP(w, r)
|
||||||
|
} else {
|
||||||
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
|
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
|
||||||
|
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||||
username, passwd, ok := r.BasicAuth()
|
}
|
||||||
if !ok {
|
}
|
||||||
http.Error(w, "Not authorized", 401)
|
|
||||||
return
|
func basicAuthWraper(h http.Handler) http.Handler {
|
||||||
}
|
return &AuthWraper{
|
||||||
|
h: h,
|
||||||
if username != config.ServerCommonCfg.DashboardUser || passwd != config.ServerCommonCfg.DashboardPwd {
|
user: config.ServerCommonCfg.DashboardUser,
|
||||||
http.Error(w, "Not authorized", 401)
|
passwd: config.ServerCommonCfg.DashboardPwd,
|
||||||
return
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
h.ServeHTTP(w, r)
|
func basicAuth(h http.HandlerFunc) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
user, passwd, hasAuth := r.BasicAuth()
|
||||||
|
if hasAuth && user == config.ServerCommonCfg.DashboardUser || passwd == config.ServerCommonCfg.DashboardPwd {
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
} else {
|
||||||
|
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
|
||||||
|
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func httprouterBasicAuth(h httprouter.Handle) httprouter.Handle {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||||
|
user, passwd, hasAuth := r.BasicAuth()
|
||||||
|
if hasAuth && user == config.ServerCommonCfg.DashboardUser || passwd == config.ServerCommonCfg.DashboardPwd {
|
||||||
|
h(w, r, ps)
|
||||||
|
} else {
|
||||||
|
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
|
||||||
|
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -434,7 +434,9 @@ func (pxy *UdpProxy) Close() {
|
|||||||
pxy.isClosed = true
|
pxy.isClosed = true
|
||||||
|
|
||||||
pxy.BaseProxy.Close()
|
pxy.BaseProxy.Close()
|
||||||
|
if pxy.workConn != nil {
|
||||||
pxy.workConn.Close()
|
pxy.workConn.Close()
|
||||||
|
}
|
||||||
pxy.udpConn.Close()
|
pxy.udpConn.Close()
|
||||||
|
|
||||||
// all channels only closed here
|
// all channels only closed here
|
||||||
|
@ -66,7 +66,7 @@
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
fetchData() {
|
fetchData() {
|
||||||
fetch('/api/serverinfo')
|
fetch('/api/serverinfo', {credentials: 'include'})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
return res.json()
|
return res.json()
|
||||||
}).then(json => {
|
}).then(json => {
|
||||||
|
@ -110,7 +110,7 @@
|
|||||||
return Humanize.fileSize(row.traffic_out)
|
return Humanize.fileSize(row.traffic_out)
|
||||||
},
|
},
|
||||||
fetchData() {
|
fetchData() {
|
||||||
fetch('/api/serverinfo')
|
fetch('/api/serverinfo', {credentials: 'include'})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
return res.json()
|
return res.json()
|
||||||
}).then(json => {
|
}).then(json => {
|
||||||
@ -119,7 +119,7 @@
|
|||||||
if (this.vhost_http_port == null || this.vhost_http_port == 0) {
|
if (this.vhost_http_port == null || this.vhost_http_port == 0) {
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
fetch('/api/proxy/http')
|
fetch('/api/proxy/http', {credentials: 'include'})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
return res.json()
|
return res.json()
|
||||||
}).then(json => {
|
}).then(json => {
|
||||||
|
@ -105,7 +105,7 @@
|
|||||||
return Humanize.fileSize(row.traffic_out)
|
return Humanize.fileSize(row.traffic_out)
|
||||||
},
|
},
|
||||||
fetchData() {
|
fetchData() {
|
||||||
fetch('/api/serverinfo')
|
fetch('/api/serverinfo', {credentials: 'include'})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
return res.json()
|
return res.json()
|
||||||
}).then(json => {
|
}).then(json => {
|
||||||
@ -114,7 +114,7 @@
|
|||||||
if (this.vhost_https_port == null || this.vhost_https_port == 0) {
|
if (this.vhost_https_port == null || this.vhost_https_port == 0) {
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
fetch('/api/proxy/https')
|
fetch('/api/proxy/https', {credentials: 'include'})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
return res.json()
|
return res.json()
|
||||||
}).then(json => {
|
}).then(json => {
|
||||||
|
@ -97,7 +97,7 @@
|
|||||||
return Humanize.fileSize(row.traffic_out)
|
return Humanize.fileSize(row.traffic_out)
|
||||||
},
|
},
|
||||||
fetchData() {
|
fetchData() {
|
||||||
fetch('/api/proxy/tcp')
|
fetch('/api/proxy/tcp', {credentials: 'include'})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
return res.json()
|
return res.json()
|
||||||
}).then(json => {
|
}).then(json => {
|
||||||
|
@ -99,7 +99,7 @@
|
|||||||
return Humanize.fileSize(row.traffic_out)
|
return Humanize.fileSize(row.traffic_out)
|
||||||
},
|
},
|
||||||
fetchData() {
|
fetchData() {
|
||||||
fetch('/api/proxy/udp')
|
fetch('/api/proxy/udp', {credentials: 'include'})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
return res.json()
|
return res.json()
|
||||||
}).then(json => {
|
}).then(json => {
|
||||||
|
@ -15,7 +15,7 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
fetchData() {
|
fetchData() {
|
||||||
let url = '/api/proxy/traffic/' + this.proxy_name
|
let url = '/api/proxy/traffic/' + this.proxy_name
|
||||||
fetch(url)
|
fetch(url, {credentials: 'include'})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
return res.json()
|
return res.json()
|
||||||
}).then(json => {
|
}).then(json => {
|
||||||
|
Loading…
Reference in New Issue
Block a user