mirror of
https://github.com/TeaOSLab/EdgeNode.git
synced 2025-11-08 03:00:27 +08:00
访问控制支持基本认证和子请求认证
This commit is contained in:
@@ -186,7 +186,7 @@ func (this *FileList) CleanPrefix(prefix string) error {
|
|||||||
|
|
||||||
var count = int64(10000)
|
var count = int64(10000)
|
||||||
for {
|
for {
|
||||||
result, err := this.db.Exec(`UPDATE "`+this.itemsTableName+`" SET expiredAt=0 WHERE id IN (SELECT id FROM "`+this.itemsTableName+`" WHERE expiredAt>0 AND createdAt<=? AND INSTR("key", ?)==1 LIMIT `+strconv.FormatInt(count, 10)+`)`, utils.UnixTime(), prefix)
|
result, err := this.db.Exec(`UPDATE "`+this.itemsTableName+`" SET expiredAt=0 WHERE id IN (SELECT id FROM "`+this.itemsTableName+`" WHERE expiredAt>0 AND createdAt<=? AND INSTR("key", ?)=1 LIMIT `+strconv.FormatInt(count, 10)+`)`, utils.UnixTime(), prefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,31 @@
|
|||||||
package caches
|
package caches
|
||||||
|
|
||||||
// 缓存内容写入接口
|
// Writer 缓存内容写入接口
|
||||||
type Writer interface {
|
type Writer interface {
|
||||||
// 写入Header数据
|
// WriteHeader 写入Header数据
|
||||||
WriteHeader(data []byte) (n int, err error)
|
WriteHeader(data []byte) (n int, err error)
|
||||||
|
|
||||||
// 写入Body数据
|
// Write 写入Body数据
|
||||||
Write(data []byte) (n int, err error)
|
Write(data []byte) (n int, err error)
|
||||||
|
|
||||||
// 写入的Header数据大小
|
// HeaderSize 写入的Header数据大小
|
||||||
HeaderSize() int64
|
HeaderSize() int64
|
||||||
|
|
||||||
// 写入的Body数据大小
|
// BodySize 写入的Body数据大小
|
||||||
BodySize() int64
|
BodySize() int64
|
||||||
|
|
||||||
// 关闭
|
// Close 关闭
|
||||||
Close() error
|
Close() error
|
||||||
|
|
||||||
// 丢弃
|
// Discard 丢弃
|
||||||
Discard() error
|
Discard() error
|
||||||
|
|
||||||
// Key
|
// Key Key
|
||||||
Key() string
|
Key() string
|
||||||
|
|
||||||
// 过期时间
|
// ExpiredAt 过期时间
|
||||||
ExpiredAt() int64
|
ExpiredAt() int64
|
||||||
|
|
||||||
// 内容类型
|
// ItemType 内容类型
|
||||||
ItemType() ItemType
|
ItemType() ItemType
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ type HTTPRequest struct {
|
|||||||
IsHTTPS bool
|
IsHTTPS bool
|
||||||
|
|
||||||
// 内部参数
|
// 内部参数
|
||||||
|
isSubRequest bool
|
||||||
writer *HTTPWriter
|
writer *HTTPWriter
|
||||||
web *serverconfigs.HTTPWebConfig // Web配置,重要提示:由于引用了别的共享的配置,所以操作中只能读取不要修改
|
web *serverconfigs.HTTPWebConfig // Web配置,重要提示:由于引用了别的共享的配置,所以操作中只能读取不要修改
|
||||||
reverseProxyRef *serverconfigs.ReverseProxyRef // 反向代理引用
|
reverseProxyRef *serverconfigs.ReverseProxyRef // 反向代理引用
|
||||||
@@ -129,7 +130,12 @@ func (this *HTTPRequest) Do() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 访问控制
|
// 访问控制
|
||||||
// TODO 需要实现
|
if !this.isSubRequest && this.web.Auth != nil && this.web.Auth.IsOn {
|
||||||
|
if this.doAuth() {
|
||||||
|
this.doEnd()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 自动跳转到HTTPS
|
// 自动跳转到HTTPS
|
||||||
if this.IsHTTP && this.web.RedirectToHttps != nil && this.web.RedirectToHttps.IsOn {
|
if this.IsHTTP && this.web.RedirectToHttps != nil && this.web.RedirectToHttps.IsOn {
|
||||||
@@ -352,6 +358,11 @@ func (this *HTTPRequest) configureWeb(web *serverconfigs.HTTPWebConfig, isTop bo
|
|||||||
this.web.FastcgiList = web.FastcgiList
|
this.web.FastcgiList = web.FastcgiList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// auth
|
||||||
|
if web.Auth != nil && (web.Auth.IsPrior || isTop) {
|
||||||
|
this.web.Auth = web.Auth
|
||||||
|
}
|
||||||
|
|
||||||
// 重写规则
|
// 重写规则
|
||||||
if len(web.RewriteRefs) > 0 {
|
if len(web.RewriteRefs) > 0 {
|
||||||
for index, ref := range web.RewriteRefs {
|
for index, ref := range web.RewriteRefs {
|
||||||
@@ -919,6 +930,11 @@ func (this *HTTPRequest) requestServerPort() int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取完整的URL
|
||||||
|
func (this *HTTPRequest) requestFullURL() string {
|
||||||
|
return this.requestScheme() + "://" + this.Host + this.uri
|
||||||
|
}
|
||||||
|
|
||||||
// 设置代理相关头部信息
|
// 设置代理相关头部信息
|
||||||
// 参考:https://tools.ietf.org/html/rfc7239
|
// 参考:https://tools.ietf.org/html/rfc7239
|
||||||
func (this *HTTPRequest) setForwardHeaders(header http.Header) {
|
func (this *HTTPRequest) setForwardHeaders(header http.Header) {
|
||||||
@@ -1149,6 +1165,11 @@ func (this *HTTPRequest) canIgnore(err error) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 已读到头
|
||||||
|
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// 网络错误
|
// 网络错误
|
||||||
_, ok := err.(*net.OpError)
|
_, ok := err.(*net.OpError)
|
||||||
if ok {
|
if ok {
|
||||||
|
|||||||
61
internal/nodes/http_request_auth.go
Normal file
61
internal/nodes/http_request_auth.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package nodes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 执行认证
|
||||||
|
func (this *HTTPRequest) doAuth() (shouldStop bool) {
|
||||||
|
if this.web.Auth == nil || !this.web.Auth.IsOn {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ref := range this.web.Auth.PolicyRefs {
|
||||||
|
if !ref.IsOn || ref.AuthPolicy == nil || !ref.AuthPolicy.IsOn {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
b, err := ref.AuthPolicy.Filter(this.RawReq, func(subReq *http.Request) (status int, err error) {
|
||||||
|
subReq.TLS = this.RawReq.TLS
|
||||||
|
subReq.RemoteAddr = this.RawReq.RemoteAddr
|
||||||
|
subReq.Host = this.RawReq.Host
|
||||||
|
subReq.Proto = this.RawReq.Proto
|
||||||
|
subReq.ProtoMinor = this.RawReq.ProtoMinor
|
||||||
|
subReq.ProtoMajor = this.RawReq.ProtoMajor
|
||||||
|
subReq.Body = ioutil.NopCloser(bytes.NewReader([]byte{}))
|
||||||
|
subReq.Header.Set("Referer", this.requestFullURL())
|
||||||
|
var writer = NewEmptyResponseWriter(this.writer)
|
||||||
|
this.doSubRequest(writer, subReq)
|
||||||
|
return writer.StatusCode(), nil
|
||||||
|
}, this.Format)
|
||||||
|
if err != nil {
|
||||||
|
this.write502(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if b {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
if ref.AuthPolicy.Type == serverconfigs.HTTPAuthTypeBasicAuth {
|
||||||
|
var method = ref.AuthPolicy.Method().(*serverconfigs.HTTPAuthBasicMethod)
|
||||||
|
var headerValue = "Basic realm=\""
|
||||||
|
if len(method.Realm) > 0 {
|
||||||
|
headerValue += method.Realm
|
||||||
|
} else {
|
||||||
|
headerValue += this.Host
|
||||||
|
}
|
||||||
|
headerValue += "\""
|
||||||
|
if len(method.Charset) > 0 {
|
||||||
|
headerValue += ", charset=\"" + method.Charset + "\""
|
||||||
|
}
|
||||||
|
this.writer.Header()["WWW-Authenticate"] = []string{headerValue}
|
||||||
|
}
|
||||||
|
this.writer.WriteHeader(http.StatusUnauthorized)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
22
internal/nodes/http_request_sub.go
Normal file
22
internal/nodes/http_request_sub.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package nodes
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
// 执行子请求
|
||||||
|
func (this *HTTPRequest) doSubRequest(writer http.ResponseWriter, rawReq *http.Request) {
|
||||||
|
// 包装新请求对象
|
||||||
|
req := &HTTPRequest{
|
||||||
|
RawReq: rawReq,
|
||||||
|
RawWriter: writer,
|
||||||
|
Server: this.Server,
|
||||||
|
Host: this.Host,
|
||||||
|
ServerName: this.ServerName,
|
||||||
|
ServerAddr: this.ServerAddr,
|
||||||
|
IsHTTP: this.IsHTTP,
|
||||||
|
IsHTTPS: this.IsHTTPS,
|
||||||
|
}
|
||||||
|
req.isSubRequest = true
|
||||||
|
req.Do()
|
||||||
|
}
|
||||||
63
internal/nodes/http_writer_empty.go
Normal file
63
internal/nodes/http_writer_empty.go
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package nodes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EmptyResponseWriter 空的响应Writer
|
||||||
|
type EmptyResponseWriter struct {
|
||||||
|
header http.Header
|
||||||
|
parentWriter http.ResponseWriter
|
||||||
|
|
||||||
|
statusCode int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEmptyResponseWriter(parentWriter http.ResponseWriter) *EmptyResponseWriter {
|
||||||
|
return &EmptyResponseWriter{
|
||||||
|
header: http.Header{},
|
||||||
|
parentWriter: parentWriter,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *EmptyResponseWriter) Header() http.Header {
|
||||||
|
return this.header
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *EmptyResponseWriter) Write(data []byte) (int, error) {
|
||||||
|
if this.statusCode > 300 && this.parentWriter != nil {
|
||||||
|
return this.parentWriter.Write(data)
|
||||||
|
}
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *EmptyResponseWriter) WriteHeader(statusCode int) {
|
||||||
|
this.statusCode = statusCode
|
||||||
|
|
||||||
|
if this.statusCode > 300 && this.parentWriter != nil {
|
||||||
|
var parentHeader = this.parentWriter.Header()
|
||||||
|
for k, v := range this.header {
|
||||||
|
parentHeader[k] = v
|
||||||
|
}
|
||||||
|
this.parentWriter.WriteHeader(this.statusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *EmptyResponseWriter) StatusCode() int {
|
||||||
|
return this.statusCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hijack Hijack
|
||||||
|
func (this *EmptyResponseWriter) Hijack() (conn net.Conn, buf *bufio.ReadWriter, err error) {
|
||||||
|
if this.parentWriter == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hijack, ok := this.parentWriter.(http.Hijacker)
|
||||||
|
if ok {
|
||||||
|
return hijack.Hijack()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user