情况:
我正在使用Gorilla的mux作为路由器构建REST API。
我想知道如何使用简单的HTTP Basic Auth保护特定路由。我不需要从文件或任何外部源读取凭据,我真的只想通过硬编码的HTTP Basic Auth用户名和密码来保护选定的路由。
问题:
在Go中这样做的惯用方法是什么? Gorilla是否提供任何东西以使其更容易?如果你能提供几行代码,那就太棒了。
答案 0 :(得分:32)
将一些答案组合成一个简单的复制/粘贴:
foreach(var foo in foos)
{
htmlOutput += $"<input asp-for='{foo.FieldName}' />";
}
请注意,// BasicAuth wraps a handler requiring HTTP basic auth for it using the given
// username and password and the specified realm, which shouldn't contain quotes.
//
// Most web browser display a dialog with something like:
//
// The website says: "<realm>"
//
// Which is really stupid so you may want to set the realm to a message rather than
// an actual realm.
func BasicAuth(handler http.HandlerFunc, username, password, realm string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user, pass, ok := r.BasicAuth()
if !ok || subtle.ConstantTimeCompare([]byte(user), []byte(username)) != 1 || subtle.ConstantTimeCompare([]byte(pass), []byte(password)) != 1 {
w.Header().Set("WWW-Authenticate", `Basic realm="`+realm+`"`)
w.WriteHeader(401)
w.Write([]byte("Unauthorised.\n"))
return
}
handler(w, r)
}
}
...
http.HandleFunc("/", BasicAuth(handleIndex, "admin", "123456", "Please enter your username and password for this site"))
仍取决于长度,因此如果您这样做,攻击者可能会计算出用户名和密码的长度。为了解决这个问题,你可以对它们进行哈希处理或添加一个固定的延迟。
答案 1 :(得分:22)
检查req.BasicAuth() https://golang.org/pkg/net/http/#Request.BasicAuth
你可以在你的处理程序中检查这个,或像这样包装你的处理程序:
func auth(fn http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user, pass, _ := r.BasicAuth()
if !check(user, pass) {
http.Error(w, "Unauthorized.", 401)
return
}
fn(w, r)
}
}
哪里
check(u, p string) bool
是您必须根据存储凭据的方式自行编写的功能。现在你可以使用:
auth(originalHandler)
之前你在哪里传递originalHandler。
[编辑:值得补充的是,您的检查功能应该能够抵抗时间攻击等侧通道攻击。存储的密码也应使用加密随机盐进行哈希处理。此外,您应该使用OAuth,让已建立的身份提供商担心密码安全。]
答案 2 :(得分:18)
截至2016年,我建议使用this answer。在任何情况下,请将您的HTTP基本身份验证包装在SSL中,以避免以纯文本形式发送用户名和密码。
将处理程序包装在另一个处理程序中,并在传入请求中使用问题WWW-Authorization标头。
示例(full version):
func checkAuth(w http.ResponseWriter, r *http.Request) bool {
s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
if len(s) != 2 { return false }
b, err := base64.StdEncoding.DecodeString(s[1])
if err != nil { return false }
pair := strings.SplitN(string(b), ":", 2)
if len(pair) != 2 { return false }
return pair[0] == "user" && pair[1] == "pass"
}
yourRouter.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if checkAuth(w, r) {
yourOriginalHandler.ServeHTTP(w, r)
return
}
w.Header().Set("WWW-Authenticate", `Basic realm="MY REALM"`)
w.WriteHeader(401)
w.Write([]byte("401 Unauthorized\n"))
})
不幸的是,std。图书馆只提供client basic auth,因此您必须这样做
自己动手或使用库,例如this one。
答案 3 :(得分:3)
net/http
请求类型具有执行此操作的辅助函数(在1.7版中测试)。一个简单版本的nemo的答案看起来像这样:
func basicAuthHandler(user, pass, realm string, next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if checkBasicAuth(r, user, pass) {
next(w, r)
return
}
w.Header().Set("WWW-Authenticate", fmt.Sprintf(`Basic realm="%s"`, realm))
w.WriteHeader(401)
w.Write([]byte("401 Unauthorized\n"))
}
}
func checkBasicAuth(r *http.Request, user, pass string) bool {
u, p, ok := r.BasicAuth()
if !ok {
return false
}
return u == user && p == pass
}
然后简单地创建具有业务逻辑的处理程序,并将其作为next
中的basicAuthHandler
参数传递,以创建一个新的&#34;包装&#34; handlerFunc。
答案 4 :(得分:2)
go-http-auth会为你做的。如果您使用net/http
,它将适合您。
答案 5 :(得分:1)
我意识到我在这里参加派对已经很晚了。我刚碰巧正在重新访问HTTP基本身份验证。经过这里的所有答案后,我实际上确定了Timmmm解决方案的变体。我甚至更进了一步,根据他的建议添加了散列以提高安全性。想想我也可以分享我的代码变体。
balance_data = read.table(file.choose(), sep=",")
attach(balance_data)
x <- balance_data[, c(2,3,4,5)]
y <- balance_data[,1]
X_train <-head(x,500)
Y_train <- head(y,100)
X_test <-tail(x,122)
str(X_train)
str(X_test)
str(Y_train)
decisionTree_Learnruntime = c()
svm_Learnruntime = c()
naivebayes_Learnruntime = c()
knn_Learnruntime = c()
decisionTree_Predictruntime = c()
svm_Predictruntime = c()
naivebayes_Predictruntime =c()
knn_Predictruntime = c()
for (i in 1:20){
library(e1071)
library(caret)
#SVM Model
start.time <- Sys.time()
svm_model <- svm(X_train,Y_train)
end.time <- Sys.time()
time.taken <- end.time - start.time
svm_Learnruntime[i]<- time.taken
#Prediction Time
start.time <- Sys.time()
pred <- predict(svm_model,X_test)
end.time <- Sys.time()
time.taken <- end.time - start.time
svm_Predictruntime[i]<- time.taken
library(rpart)
#Decision Tree
#Learn Time
start.time <- Sys.time()
tree_model <- rpart(X_train,Y_train)
end.time <- Sys.time()
time.taken <- end.time - start.time
decisionTree_Learnruntime[i]<- time.taken
#Prediction Time
start.time <- Sys.time()
pred = predict(tree_model,X_test)
end.time <- Sys.time()
time.taken <- end.time - start.time
decisionTree_Predictruntime[i] <- time.taken
library(e1071)
#Naive Bayes
#Learn Time
start.time <- Sys.time()
naive_model <-naiveBayes(X_train,Y_train)
end.time <- Sys.time()
time.taken <- end.time - start.time
naivebayes_Learnruntime[i]<- time.taken
#Prediction Time
start.time <- Sys.time()
pred = predict(naive_model,X_test)
end.time <- Sys.time()
time.taken <- end.time - start.time
naivebayes_Predictruntime [i]<- time.taken
}
svm_Learnruntime
svm_Predictruntime
decisionTree_Learnruntime
decisionTree_Predictruntime
naivebayes_Learnruntime
naivebayes_Predictruntime