| 227 | } |
| 228 | |
| 229 | func BasicAuth(u, p string, next http.Handler) http.Handler { |
| 230 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 231 | // Extract the username and password from the request |
| 232 | // Authorization header. If no Authentication header is present |
| 233 | // or the header value is invalid, then the 'ok' return value |
| 234 | // will be false. |
| 235 | username, password, ok := r.BasicAuth() |
| 236 | if ok { |
| 237 | // Calculate SHA-256 hashes for the provided and expected |
| 238 | // usernames and passwords. |
| 239 | usernameHash := sha256.Sum256([]byte(username)) |
| 240 | passwordHash := sha256.Sum256([]byte(password)) |
| 241 | expectedUsernameHash := sha256.Sum256([]byte(u)) |
| 242 | expectedPasswordHash := sha256.Sum256([]byte(p)) |
| 243 | |
| 244 | // 使用 subtle.ConstantTimeCompare() 进行校验 |
| 245 | // the provided username and password hashes equal the |
| 246 | // expected username and password hashes. ConstantTimeCompare |
| 247 | // 如果值相等,则返回1,否则返回0。 |
| 248 | // Importantly, we should to do the work to evaluate both the |
| 249 | // username and password before checking the return values to |
| 250 | // 避免泄露信息。 |
| 251 | usernameMatch := (subtle.ConstantTimeCompare(usernameHash[:], expectedUsernameHash[:]) == 1) |
| 252 | passwordMatch := (subtle.ConstantTimeCompare(passwordHash[:], expectedPasswordHash[:]) == 1) |
| 253 | |
| 254 | // If the username and password are correct, then call |
| 255 | // the next handler in the chain. Make sure to return |
| 256 | // afterwards, so that none of the code below is run. |
| 257 | if usernameMatch && passwordMatch { |
| 258 | if next != nil { |
| 259 | next.ServeHTTP(w, r) |
| 260 | } |
| 261 | return |
| 262 | } |
| 263 | } |
| 264 | |
| 265 | // If the Authentication header is not present, is invalid, or the |
| 266 | // username or password is wrong, then set a WWW-Authenticate |
| 267 | // header to inform the client that we expect them to use basic |
| 268 | // authentication and send a 401 Unauthorized response. |
| 269 | w.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`) |
| 270 | http.Error(w, "Unauthorized", http.StatusUnauthorized) |
| 271 | }) |
| 272 | } |