generated from qiangxue/go-rest-api
-
Notifications
You must be signed in to change notification settings - Fork 0
/
service.go
69 lines (59 loc) · 2.23 KB
/
service.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package auth
import (
"context"
"github.com/dgrijalva/jwt-go"
"github.com/qiangxue/go-rest-api/internal/entity"
"github.com/qiangxue/go-rest-api/internal/errors"
"github.com/qiangxue/go-rest-api/pkg/log"
"time"
)
// Service encapsulates the authentication logic.
type Service interface {
// authenticate authenticates a user using username and password.
// It returns a JWT token if authentication succeeds. Otherwise, an error is returned.
Login(ctx context.Context, username, password string) (string, error)
}
// Identity represents an authenticated user identity.
type Identity interface {
// GetID returns the user ID.
GetID() string
// GetName returns the user name.
GetName() string
}
type service struct {
signingKey string
tokenExpiration int
logger log.Logger
}
// NewService creates a new authentication service.
func NewService(signingKey string, tokenExpiration int, logger log.Logger) Service {
return service{signingKey, tokenExpiration, logger}
}
// Login authenticates a user and generates a JWT token if authentication succeeds.
// Otherwise, an error is returned.
func (s service) Login(ctx context.Context, username, password string) (string, error) {
if identity := s.authenticate(ctx, username, password); identity != nil {
return s.generateJWT(identity)
}
return "", errors.Unauthorized("")
}
// authenticate authenticates a user using username and password.
// If username and password are correct, an identity is returned. Otherwise, nil is returned.
func (s service) authenticate(ctx context.Context, username, password string) Identity {
logger := s.logger.With(ctx, "user", username)
// TODO: the following authentication logic is only for demo purpose
if username == "demo" && password == "pass" {
logger.Infof("authentication successful")
return entity.User{ID: "100", Name: "demo"}
}
logger.Infof("authentication failed")
return nil
}
// generateJWT generates a JWT that encodes an identity.
func (s service) generateJWT(identity Identity) (string, error) {
return jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"id": identity.GetID(),
"name": identity.GetName(),
"exp": time.Now().Add(time.Duration(s.tokenExpiration) * time.Hour).Unix(),
}).SignedString([]byte(s.signingKey))
}