Dragonfly2
138 строк · 3.2 Кб
1/*
2* Copyright 2020 The Dragonfly Authors
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8* http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15*/
16
17package middlewares
18
19import (
20"context"
21"net/http"
22"time"
23
24jwt "github.com/appleboy/gin-jwt/v2"
25"github.com/gin-gonic/gin"
26
27"d7y.io/dragonfly/v2/manager/config"
28"d7y.io/dragonfly/v2/manager/models"
29"d7y.io/dragonfly/v2/manager/service"
30"d7y.io/dragonfly/v2/manager/types"
31)
32
33const (
34// defaultIdentityKey is default of the identity key.
35defaultIdentityKey = "id"
36)
37
38func Jwt(cfg config.JWTConfig, service service.Service) (*jwt.GinJWTMiddleware, error) {
39authMiddleware, err := jwt.New(&jwt.GinJWTMiddleware{
40Realm: cfg.Realm,
41Key: []byte(cfg.Key),
42Timeout: cfg.Timeout,
43MaxRefresh: cfg.MaxRefresh,
44IdentityKey: defaultIdentityKey,
45
46IdentityHandler: func(c *gin.Context) any {
47claims := jwt.ExtractClaims(c)
48
49id, ok := claims[defaultIdentityKey]
50if !ok {
51c.JSON(http.StatusUnauthorized, gin.H{
52"message": "Unavailable token: require user id",
53})
54c.Abort()
55return nil
56}
57
58c.Set("id", id)
59return id
60},
61
62Authenticator: func(c *gin.Context) (any, error) {
63// Oauth2 signin
64if rawUser, ok := c.Get("user"); ok {
65user, ok := rawUser.(*models.User)
66if !ok {
67return "", jwt.ErrFailedAuthentication
68}
69return user, nil
70}
71
72// Normal signin
73var json types.SignInRequest
74if err := c.ShouldBindJSON(&json); err != nil {
75return "", jwt.ErrMissingLoginValues
76}
77
78user, err := service.SignIn(context.TODO(), json)
79if err != nil {
80return "", jwt.ErrFailedAuthentication
81}
82
83return user, nil
84},
85
86PayloadFunc: func(data any) jwt.MapClaims {
87if user, ok := data.(*models.User); ok {
88return jwt.MapClaims{
89defaultIdentityKey: user.ID,
90}
91}
92
93return jwt.MapClaims{}
94},
95
96Unauthorized: func(c *gin.Context, code int, message string) {
97c.JSON(code, gin.H{
98"message": http.StatusText(code),
99})
100},
101
102LoginResponse: func(c *gin.Context, code int, token string, expire time.Time) {
103// Oauth2 signin
104if _, ok := c.Get("user"); ok {
105c.Redirect(http.StatusFound, "/")
106return
107}
108
109// Normal signin
110c.JSON(code, gin.H{
111"token": token,
112"expire": expire.Format(time.RFC3339),
113})
114},
115
116LogoutResponse: func(c *gin.Context, code int) {
117c.Status(code)
118},
119
120RefreshResponse: func(c *gin.Context, code int, token string, expire time.Time) {
121c.JSON(code, gin.H{
122"token": token,
123"expire": expire.Format(time.RFC3339),
124})
125},
126
127TokenLookup: "cookie: jwt, header: Authorization, query: token",
128TokenHeadName: "Bearer",
129TimeFunc: time.Now,
130SendCookie: true,
131CookieHTTPOnly: false,
132})
133if err != nil {
134return nil, err
135}
136
137return authMiddleware, nil
138}
139