mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-16 05:16:35 +08:00
feat: add Error if the request can't be authorized
This commit is contained in:
parent
eac2daac64
commit
a24db1f9f9
7
auth.go
7
auth.go
@ -7,6 +7,7 @@ package gin
|
|||||||
import (
|
import (
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@ -26,6 +27,11 @@ type authPair struct {
|
|||||||
|
|
||||||
type authPairs []authPair
|
type authPairs []authPair
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrUnauthorized cannot authorize the request.
|
||||||
|
ErrUnauthorized = errors.New("unauthorized")
|
||||||
|
)
|
||||||
|
|
||||||
func (a authPairs) searchCredential(authValue string) (string, bool) {
|
func (a authPairs) searchCredential(authValue string) (string, bool) {
|
||||||
if authValue == "" {
|
if authValue == "" {
|
||||||
return "", false
|
return "", false
|
||||||
@ -53,6 +59,7 @@ func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc {
|
|||||||
user, found := pairs.searchCredential(c.requestHeader("Authorization"))
|
user, found := pairs.searchCredential(c.requestHeader("Authorization"))
|
||||||
if !found {
|
if !found {
|
||||||
// Credentials doesn't match, we return 401 and abort handlers chain.
|
// Credentials doesn't match, we return 401 and abort handlers chain.
|
||||||
|
c.Error(ErrUnauthorized)
|
||||||
c.Header("WWW-Authenticate", realm)
|
c.Header("WWW-Authenticate", realm)
|
||||||
c.AbortWithStatus(http.StatusUnauthorized)
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
|
24
auth_test.go
24
auth_test.go
@ -137,3 +137,27 @@ func TestBasicAuth401WithCustomRealm(t *testing.T) {
|
|||||||
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
||||||
assert.Equal(t, "Basic realm=\"My Custom \\\"Realm\\\"\"", w.Header().Get("WWW-Authenticate"))
|
assert.Equal(t, "Basic realm=\"My Custom \\\"Realm\\\"\"", w.Header().Get("WWW-Authenticate"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBasicAuthWithMiddleware(t *testing.T) {
|
||||||
|
called := false
|
||||||
|
router := New()
|
||||||
|
router.Use(func(c *Context) {
|
||||||
|
called = true
|
||||||
|
c.Next()
|
||||||
|
if c.Errors.Last().Err == ErrUnauthorized {
|
||||||
|
c.JSON(401, H{"message": "Begone!"})
|
||||||
|
}
|
||||||
|
}, BasicAuth(Accounts{"foo": "bar"}))
|
||||||
|
router.GET("/login", func(c *Context) {
|
||||||
|
c.String(http.StatusOK, c.MustGet(AuthUserKey).(string))
|
||||||
|
})
|
||||||
|
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
req, _ := http.NewRequest("GET", "/login", nil)
|
||||||
|
req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("admin:password")))
|
||||||
|
router.ServeHTTP(w, req)
|
||||||
|
|
||||||
|
assert.True(t, called)
|
||||||
|
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
||||||
|
assert.JSONEq(t, `{"message": "Begone!"}`, w.Body.String())
|
||||||
|
}
|
||||||
|
21
docs/doc.md
21
docs/doc.md
@ -46,6 +46,7 @@
|
|||||||
- [Redirects](#redirects)
|
- [Redirects](#redirects)
|
||||||
- [Custom Middleware](#custom-middleware)
|
- [Custom Middleware](#custom-middleware)
|
||||||
- [Using BasicAuth() middleware](#using-basicauth-middleware)
|
- [Using BasicAuth() middleware](#using-basicauth-middleware)
|
||||||
|
- [Detecting authorization failure in custom middleware](#detecting-authorization-failure-in-custom-middleware)
|
||||||
- [Goroutines inside a middleware](#goroutines-inside-a-middleware)
|
- [Goroutines inside a middleware](#goroutines-inside-a-middleware)
|
||||||
- [Custom HTTP configuration](#custom-http-configuration)
|
- [Custom HTTP configuration](#custom-http-configuration)
|
||||||
- [Support Let's Encrypt](#support-lets-encrypt)
|
- [Support Let's Encrypt](#support-lets-encrypt)
|
||||||
@ -1468,6 +1469,26 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Detecting authorization failure in custom middleware
|
||||||
|
|
||||||
|
When the `BasicAuth` middleware fails authorization, an `Error` is added to the `gin.Context.Errors` slice. You can detect this failure in a custom middleware with code like this:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func main() {
|
||||||
|
router := New()
|
||||||
|
router.Use(func(c *Context) {
|
||||||
|
c.Next()
|
||||||
|
if c.Errors.Last().Err == ErrUnauthorized {
|
||||||
|
// Unauthorized detected, act accordingly
|
||||||
|
}
|
||||||
|
})
|
||||||
|
router.Use(BasicAuth(Accounts{"admin": "password"}))
|
||||||
|
router.GET("/login", func(c *Context) {
|
||||||
|
c.String(http.StatusOK, c.MustGet(AuthUserKey).(string))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Goroutines inside a middleware
|
### Goroutines inside a middleware
|
||||||
|
|
||||||
When starting new Goroutines inside a middleware or handler, you **SHOULD NOT** use the original context inside it, you have to use a read-only copy.
|
When starting new Goroutines inside a middleware or handler, you **SHOULD NOT** use the original context inside it, you have to use a read-only copy.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user