diff --git a/vblog/apps/token/impl/impl.go b/vblog/apps/token/impl/impl.go
index 773ede9..2950dbe 100644
--- a/vblog/apps/token/impl/impl.go
+++ b/vblog/apps/token/impl/impl.go
@@ -2,20 +2,53 @@ package impl
import (
"context"
+ "fmt"
+ "github.com/infraboard/mcube/v2/exception"
+ "github.com/infraboard/mcube/v2/ioc/config/datasource"
"gitlab.com/go-course-project/go17/vblog/apps/token"
+ "gitlab.com/go-course-project/go17/vblog/apps/user"
+ "gitlab.com/go-course-project/go17/vblog/apps/user/impl"
)
-var TokenService token.Service = &TokenServiceImpl{}
+var TokenService token.Service = &TokenServiceImpl{
+ user: impl.UserService,
+}
// 定义一个struct, 用于实现 UserService就是刚才定义的接口
// 怎么才能判断这个结构体没有实现这个接口
type TokenServiceImpl struct {
+ // user service
+ user user.AdminService
}
// IssueToken implements token.Service.
-func (t *TokenServiceImpl) IssueToken(context.Context, *token.IssueTokenRequest) (*token.Token, error) {
- panic("unimplemented")
+func (t *TokenServiceImpl) IssueToken(ctx context.Context, in *token.IssueTokenRequest) (*token.Token, error) {
+ if err := in.Validate(); err != nil {
+ return nil, exception.NewBadRequest("参数校验异常: %s", err)
+ }
+ // 1. 查询用户
+ u, err := t.user.DescribeUser(ctx, &user.DescribeUserRequest{
+ DescribeBy: user.DESCRIBE_BY_USERNAME,
+ Value: in.Username,
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ // 2. 比对密码
+ if err := u.CheckPassword(in.Password); err != nil {
+ return nil, err
+ }
+
+ // 3. 颁发Token
+ tk := token.NewToken(fmt.Sprintf("%d", u.Id)).SetRefUserName(u.Username)
+
+ if err := datasource.DBFromCtx(ctx).Create(tk).Error; err != nil {
+ return nil, err
+ }
+
+ return tk, nil
}
// RevolkToken implements token.Service.
@@ -24,6 +57,17 @@ func (t *TokenServiceImpl) RevolkToken(context.Context, *token.RevolkTokenReques
}
// ValidateToken implements token.Service.
-func (t *TokenServiceImpl) ValidateToken(context.Context, *token.ValidateTokenRequest) (*token.Token, error) {
- panic("unimplemented")
+// 1. 这个令牌是不是我们发
+// 2. 这个令牌有没有过期
+func (t *TokenServiceImpl) ValidateToken(ctx context.Context, in *token.ValidateTokenRequest) (*token.Token, error) {
+ tk := &token.Token{}
+ if err := datasource.DBFromCtx(ctx).Where("access_token = ?", in.AccessToken).Take(tk).Error; err != nil {
+ return nil, err
+ }
+
+ if err := tk.IsAccessTokenExpired(); err != nil {
+ return nil, err
+ }
+
+ return tk, nil
}
diff --git a/vblog/apps/token/impl_test.go b/vblog/apps/token/impl_test.go
new file mode 100644
index 0000000..6d1e7db
--- /dev/null
+++ b/vblog/apps/token/impl_test.go
@@ -0,0 +1,37 @@
+package token_test
+
+import (
+ "context"
+ "testing"
+
+ "gitlab.com/go-course-project/go17/vblog/apps/token"
+ "gitlab.com/go-course-project/go17/vblog/apps/token/impl"
+)
+
+var (
+ ctx = context.Background()
+)
+
+// 我要测试的对象是什么?, 这个服务的具体实现
+// Service的具体实现?现在还没实现
+// $2a$10$yHVSVuyIpTrQxwiuZUwSMuaJFsnd4YBd6hgA.31xNzuyTu4voD/QW
+// $2a$10$fe0lsMhM15i4cjHmWudroOOIIBR27Nb7vwrigwK.9PhWdFld44Yze
+// $2a$10$RoR0qK37vfc7pddPV0mpU.nN15Lv8745A40MkCJLe47Q00Ag83Qru
+// https://gitee.com/infraboard/go-course/blob/master/day09/go-hash.md#bcrypt
+func TestIssueToken(t *testing.T) {
+ req := token.NewIssueTokenRequest("admin", "123456")
+ ins, err := impl.TokenService.IssueToken(ctx, req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Log(ins)
+}
+
+func TestValidateToken(t *testing.T) {
+ req := token.NewValidateTokenRequest("51bf49f5-12a2-406a-baf8-3f99d985b41a")
+ ins, err := impl.TokenService.ValidateToken(ctx, req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Log(ins)
+}
diff --git a/vblog/apps/token/interface.go b/vblog/apps/token/interface.go
index e7fa75b..b9152d7 100644
--- a/vblog/apps/token/interface.go
+++ b/vblog/apps/token/interface.go
@@ -1,6 +1,10 @@
package token
-import "context"
+import (
+ "context"
+
+ "github.com/infraboard/mcube/v2/ioc/config/validator"
+)
// 业务域
type Service interface {
@@ -23,19 +27,36 @@ type RevolkTokenRequest struct {
RefreshToken string `json:"refresh_token"`
}
+func NewIssueTokenRequest(username, password string) *IssueTokenRequest {
+ return &IssueTokenRequest{
+ Username: username,
+ Password: password,
+ }
+}
+
type IssueTokenRequest struct {
- Username string `json:"username"`
- Password string `json:"password"`
+ Username string `json:"username" validate:"required"`
+ Password string `json:"password" validate:"required"`
// 记住我, Token可能1天过期, 过去时间调整为7天
RememberMe bool `json:"remember_me"`
}
+func (r *IssueTokenRequest) Validate() error {
+ return validator.Validate(r)
+}
+
// 内部
type InnterService interface {
// 令牌校验
ValidateToken(context.Context, *ValidateTokenRequest) (*Token, error)
}
+func NewValidateTokenRequest(at string) *ValidateTokenRequest {
+ return &ValidateTokenRequest{
+ AccessToken: at,
+ }
+}
+
type ValidateTokenRequest struct {
// 访问令牌
AccessToken string `json:"access_token"`
diff --git a/vblog/apps/token/model.go b/vblog/apps/token/model.go
index bdc49c2..7463b3d 100644
--- a/vblog/apps/token/model.go
+++ b/vblog/apps/token/model.go
@@ -1,6 +1,25 @@
package token
-import "time"
+import (
+ "time"
+
+ "github.com/google/uuid"
+ "github.com/infraboard/mcube/v2/exception"
+ "github.com/infraboard/mcube/v2/tools/pretty"
+)
+
+func NewToken(refUserId string) *Token {
+ aExpiredAt := time.Now().AddDate(0, 0, 1)
+ rExpiredAt := time.Now().AddDate(0, 0, 7)
+ return &Token{
+ RefUserId: refUserId,
+ AccessToken: uuid.NewString(),
+ AccessTokenExpireAt: &aExpiredAt,
+ IssueAt: time.Now(),
+ RefreshToken: uuid.NewString(),
+ RefreshTokenExpireAt: &rExpiredAt,
+ }
+}
// 用户的身份令牌
type Token struct {
@@ -24,6 +43,35 @@ type Token struct {
RefUserName string `json:"ref_user_name" gorm:"-"`
}
+func (r *Token) String() string {
+ return pretty.ToJSON(r)
+}
+
func (t *Token) TableName() string {
return "tokens"
}
+
+func (r *Token) IsAccessTokenExpired() error {
+ if r.AccessTokenExpireAt == nil {
+ return nil
+ }
+ if time.Now().After(*r.AccessTokenExpireAt) {
+ return exception.NewAccessTokenExpired("%s 已过期", r.AccessToken)
+ }
+ return nil
+}
+
+func (r *Token) IsRefreshTokenExpired() error {
+ if r.RefreshTokenExpireAt == nil {
+ return nil
+ }
+ if time.Now().After(*r.RefreshTokenExpireAt) {
+ return exception.NewAccessTokenExpired("%s 已过期", r.RefreshTokenExpireAt)
+ }
+ return nil
+}
+
+func (t *Token) SetRefUserName(refUserName string) *Token {
+ t.RefUserName = refUserName
+ return t
+}
diff --git a/vblog/docs/token_expired.drawio b/vblog/docs/token_expired.drawio
new file mode 100644
index 0000000..254be50
--- /dev/null
+++ b/vblog/docs/token_expired.drawio
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vblog/docs/transation.drawio b/vblog/docs/transation.drawio
index d5a4a23..0aa8c70 100644
--- a/vblog/docs/transation.drawio
+++ b/vblog/docs/transation.drawio
@@ -1,6 +1,6 @@
-
+
@@ -31,6 +31,9 @@
+
+
+