diff --git a/.golangci.yaml b/.golangci.yaml index 3cc10f2..a7d6a77 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -117,13 +117,13 @@ issues: - gocognit - contextcheck - exclude-dirs: - - internal/logic +# exclude-dirs: +# - internal/logic exclude-files: - .*_test.go - - permission_tree.go - - role_permission.go +# - permission_tree.go +# - role_permission.go diff --git a/generate/protobuf/permission.proto b/generate/protobuf/permission.proto index 62f547e..f6a0c20 100644 --- a/generate/protobuf/permission.proto +++ b/generate/protobuf/permission.proto @@ -19,10 +19,16 @@ message AuthorizationReq { string scope = 3; // data 是一個通用的 key-value 結構,用於存儲額外數據 map data = 4; - // expires 表示過期時間 - int32 expires = 5; // is_refresh_token 表示是否為刷新令牌 - bool is_refresh_token = 6; + bool is_refresh_token = 5; + // 發送token 的 uid + string uid =6; + // 發送token 的 account + string account = 7; + // expires 表示過期時間(unixnamo utc 時間) + optional int64 expires = 8; + // expires 表示過期時間(unixnamo utc 時間) + optional int64 refreshExpire = 9; } // TokenResp 定義訪問令牌響應的結構 @@ -32,24 +38,14 @@ message TokenResp { // token_type 表示令牌類型 string token_type = 2; // expires_in 表示令牌過期時間 - int32 expires_in = 3; + int64 expires_in = 3; // refresh_token 表示刷新令牌 string refresh_token = 4; } -// CreateOneTimeTokenReq 建立一次性使用的 token, -// 要帶比較長久的 token 來,驗證後才可以 -message CreateOneTimeTokenReq { - string token = 1; -} - -message CreateOneTimeTokenResp { - string one_time_token = 1; -} - // RefreshTokenReq 更新 Token message RefreshTokenReq { - string token = 1; + string token = 1; // refresh token string scope = 2; int64 expires = 3; string device_id = 4; @@ -95,7 +91,7 @@ message Token { // ID 表示令牌的唯一標識符 string id = 1; // client_id 表示客戶端 ID - int32 client_id = 2; + int64 client_id = 2; // uid 表示用戶 ID string uid = 3; // device_id 表示設備 ID @@ -103,13 +99,13 @@ message Token { // access_token 表示訪問令牌 string access_token = 5; // expires_in 表示訪問令牌的過期時間(秒) - int32 expires_in = 6; + int64 expires_in = 6; // access_create_at 表示訪問令牌的創建時間 int64 access_create_at = 7; // refresh_token 表示刷新令牌 string refresh_token = 8; // refresh_expires_in 表示刷新令牌的過期時間(秒) - int32 refresh_expires_in = 9; + int64 refresh_expires_in = 9; // refresh_create_at 表示刷新令牌的創建時間 int64 refresh_create_at = 10; } @@ -123,10 +119,6 @@ message Tokens{ repeated TokenResp token = 1; } -message CancelOneTimeTokenReq { - repeated string token = 1; -} - // 跟 Token 相關的大小事,這次只回應錯誤,以及結果,不統一規範 // 錯誤碼應該在 Biz GW 在做回應,另外我這邊取名字比較通用, // access_token -> token , refresh_token -> one_time_token @@ -141,14 +133,10 @@ service TokenService { rpc ValidationToken(ValidationTokenReq) returns(ValidationTokenResp); // CancelTokens 取消 Token 從UID 視角,以及 token id 視角出發, UID 登出,底下所有 Device ID 也要登出, Token ID 登出, 所有 UID + Device 都要登出 rpc CancelTokens(DoTokenByUIDReq) returns(OKResp); - // CancelTokenByDeviceId 取消 Token, 從 Device 視角出發,可以選,登出這個Device 下所有 token ,登出這個Device 下指定token - rpc CancelTokenByDeviceId(DoTokenByDeviceIDReq) returns(OKResp); - // GetUserTokensByDeviceId 取得目前所對應的 DeviceID 所存在的 Tokens - rpc GetUserTokensByDeviceId(DoTokenByDeviceIDReq) returns(Tokens); - // GetUserTokensByUid 取得目前所對應的 UID 所存在的 Tokens - rpc GetUserTokensByUid(QueryTokenByUIDReq) returns(Tokens); - // NewOneTimeToken 建立一次性使用,例如:RefreshToken - rpc NewOneTimeToken(CreateOneTimeTokenReq) returns(CreateOneTimeTokenResp); - // CancelOneTimeToken 取消一次性使用 - rpc CancelOneTimeToken(CancelOneTimeTokenReq) returns(OKResp); + // CancelTokenByDeviceID 取消 Token, 從 Device 視角出發,可以選,登出這個Device 下所有 token ,登出這個Device 下指定token + rpc CancelTokenByDeviceID(DoTokenByDeviceIDReq) returns(OKResp); + // GetUserTokensByDeviceID 取得目前所對應的 DeviceID 所存在的 Tokens + rpc GetUserTokensByDeviceID(DoTokenByDeviceIDReq) returns(Tokens); + // GetUserTokensByUID 取得目前所對應的 UID 所存在的 Tokens + rpc GetUserTokensByUID(QueryTokenByUIDReq) returns(Tokens); } diff --git a/internal/config/config.go b/internal/config/config.go index c1f85b9..f83c0c3 100755 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1,7 +1,21 @@ package config -import "github.com/zeromicro/go-zero/zrpc" +import ( + "time" + + "github.com/zeromicro/go-zero/core/stores/redis" + "github.com/zeromicro/go-zero/zrpc" +) type Config struct { zrpc.RpcServerConf + + // Redis Cluster + RedisCluster redis.RedisConf + + Token struct { + RefreshExpires time.Duration + Expired time.Duration + Secret string + } } diff --git a/internal/logic/tokenservice/cancel_one_time_token_logic.go b/internal/logic/tokenservice/cancel_one_time_token_logic.go deleted file mode 100644 index 3a0376c..0000000 --- a/internal/logic/tokenservice/cancel_one_time_token_logic.go +++ /dev/null @@ -1,31 +0,0 @@ -package tokenservicelogic - -import ( - "context" - - "code.30cm.net/digimon/app-cloudep-permission-server/gen_result/pb/permission" - "code.30cm.net/digimon/app-cloudep-permission-server/internal/svc" - - "github.com/zeromicro/go-zero/core/logx" -) - -type CancelOneTimeTokenLogic struct { - ctx context.Context - svcCtx *svc.ServiceContext - logx.Logger -} - -func NewCancelOneTimeTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CancelOneTimeTokenLogic { - return &CancelOneTimeTokenLogic{ - ctx: ctx, - svcCtx: svcCtx, - Logger: logx.WithContext(ctx), - } -} - -// CancelOneTimeToken 取消一次性使用 -func (l *CancelOneTimeTokenLogic) CancelOneTimeToken(in *permission.CancelOneTimeTokenReq) (*permission.OKResp, error) { - // todo: add your logic here and delete this line - - return &permission.OKResp{}, nil -} diff --git a/internal/logic/tokenservice/cancel_token_by_device_id_logic.go b/internal/logic/tokenservice/cancel_token_by_device_i_d_logic.go similarity index 56% rename from internal/logic/tokenservice/cancel_token_by_device_id_logic.go rename to internal/logic/tokenservice/cancel_token_by_device_i_d_logic.go index 7a3a63a..99ef5ad 100644 --- a/internal/logic/tokenservice/cancel_token_by_device_id_logic.go +++ b/internal/logic/tokenservice/cancel_token_by_device_i_d_logic.go @@ -9,23 +9,26 @@ import ( "github.com/zeromicro/go-zero/core/logx" ) -type CancelTokenByDeviceIdLogic struct { +type CancelTokenByDeviceIDLogic struct { ctx context.Context svcCtx *svc.ServiceContext logx.Logger } -func NewCancelTokenByDeviceIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CancelTokenByDeviceIdLogic { - return &CancelTokenByDeviceIdLogic{ +func NewCancelTokenByDeviceIDLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CancelTokenByDeviceIDLogic { + return &CancelTokenByDeviceIDLogic{ ctx: ctx, svcCtx: svcCtx, Logger: logx.WithContext(ctx), } } -// CancelTokenByDeviceId 取消 Token, 從 Device 視角出發,可以選,登出這個Device 下所有 token ,登出這個Device 下指定token -func (l *CancelTokenByDeviceIdLogic) CancelTokenByDeviceId(in *permission.DoTokenByDeviceIDReq) (*permission.OKResp, error) { - // todo: add your logic here and delete this line +// CancelTokenByDeviceID 取消 Token, 從 Device 視角出發,可以選,登出這個Device 下所有 token ,登出這個Device 下指定token +func (l *CancelTokenByDeviceIDLogic) CancelTokenByDeviceID(in *permission.DoTokenByDeviceIDReq) (*permission.OKResp, error) { + err := l.svcCtx.TokenUseCase.RevokeTokensByDeviceID(l.ctx, in.GetDeviceId()) + if err != nil { + return nil, err + } return &permission.OKResp{}, nil } diff --git a/internal/logic/tokenservice/cancel_token_logic.go b/internal/logic/tokenservice/cancel_token_logic.go index 322f8d6..b7d8cc5 100644 --- a/internal/logic/tokenservice/cancel_token_logic.go +++ b/internal/logic/tokenservice/cancel_token_logic.go @@ -3,6 +3,8 @@ package tokenservicelogic import ( "context" + "code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/usecase" + "code.30cm.net/digimon/app-cloudep-permission-server/gen_result/pb/permission" "code.30cm.net/digimon/app-cloudep-permission-server/internal/svc" @@ -25,7 +27,12 @@ func NewCancelTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Cance // CancelToken 取消 Token,也包含他裡面的 One Time Toke func (l *CancelTokenLogic) CancelToken(in *permission.CancelTokenReq) (*permission.OKResp, error) { - // todo: add your logic here and delete this line + err := l.svcCtx.TokenUseCase.RevokeToken(l.ctx, usecase.TokenRequest{ + Token: in.GetToken(), + }) + if err != nil { + return nil, err + } return &permission.OKResp{}, nil } diff --git a/internal/logic/tokenservice/cancel_tokens_logic.go b/internal/logic/tokenservice/cancel_tokens_logic.go index 2e1a0d3..b42498c 100644 --- a/internal/logic/tokenservice/cancel_tokens_logic.go +++ b/internal/logic/tokenservice/cancel_tokens_logic.go @@ -3,6 +3,8 @@ package tokenservicelogic import ( "context" + "code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/usecase" + "code.30cm.net/digimon/app-cloudep-permission-server/gen_result/pb/permission" "code.30cm.net/digimon/app-cloudep-permission-server/internal/svc" @@ -25,7 +27,19 @@ func NewCancelTokensLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Canc // CancelTokens 取消 Token 從UID 視角,以及 token id 視角出發, UID 登出,底下所有 Device ID 也要登出, Token ID 登出, 所有 UID + Device 都要登出 func (l *CancelTokensLogic) CancelTokens(in *permission.DoTokenByUIDReq) (*permission.OKResp, error) { - // todo: add your logic here and delete this line + req := usecase.RevokeTokensByUIDRequest{} + if in.GetUid() != "" { + req.UID = in.GetUid() + } + + if len(in.GetIds()) > 0 { + req.IDs = in.GetIds() + } + + err := l.svcCtx.TokenUseCase.RevokeTokensByUID(l.ctx, req) + if err != nil { + return nil, err + } return &permission.OKResp{}, nil } diff --git a/internal/logic/tokenservice/get_user_tokens_by_device_i_d_logic.go b/internal/logic/tokenservice/get_user_tokens_by_device_i_d_logic.go new file mode 100644 index 0000000..f8fae3b --- /dev/null +++ b/internal/logic/tokenservice/get_user_tokens_by_device_i_d_logic.go @@ -0,0 +1,49 @@ +package tokenservicelogic + +import ( + "context" + + "code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/token" + + "code.30cm.net/digimon/app-cloudep-permission-server/gen_result/pb/permission" + "code.30cm.net/digimon/app-cloudep-permission-server/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type GetUserTokensByDeviceIDLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewGetUserTokensByDeviceIDLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserTokensByDeviceIDLogic { + return &GetUserTokensByDeviceIDLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// GetUserTokensByDeviceID 取得目前所對應的 DeviceID 所存在的 Tokens +func (l *GetUserTokensByDeviceIDLogic) GetUserTokensByDeviceID(in *permission.DoTokenByDeviceIDReq) (*permission.Tokens, error) { + id, err := l.svcCtx.TokenUseCase.GetUserTokensByDeviceID(l.ctx, in.GetDeviceId()) + if err != nil { + return nil, err + } + tokenType := token.Bearer + + result := make([]*permission.TokenResp, 0, len(id)) + for _, v := range id { + result = append(result, &permission.TokenResp{ + AccessToken: v.AccessToken, + ExpiresIn: v.ExpiresIn, + RefreshToken: v.RefreshToken, + TokenType: tokenType.ToString(), + }) + } + + return &permission.Tokens{ + Token: result, + }, nil +} diff --git a/internal/logic/tokenservice/get_user_tokens_by_device_id_logic.go b/internal/logic/tokenservice/get_user_tokens_by_device_id_logic.go deleted file mode 100644 index 3b53d91..0000000 --- a/internal/logic/tokenservice/get_user_tokens_by_device_id_logic.go +++ /dev/null @@ -1,31 +0,0 @@ -package tokenservicelogic - -import ( - "context" - - "code.30cm.net/digimon/app-cloudep-permission-server/gen_result/pb/permission" - "code.30cm.net/digimon/app-cloudep-permission-server/internal/svc" - - "github.com/zeromicro/go-zero/core/logx" -) - -type GetUserTokensByDeviceIdLogic struct { - ctx context.Context - svcCtx *svc.ServiceContext - logx.Logger -} - -func NewGetUserTokensByDeviceIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserTokensByDeviceIdLogic { - return &GetUserTokensByDeviceIdLogic{ - ctx: ctx, - svcCtx: svcCtx, - Logger: logx.WithContext(ctx), - } -} - -// GetUserTokensByDeviceId 取得目前所對應的 DeviceID 所存在的 Tokens -func (l *GetUserTokensByDeviceIdLogic) GetUserTokensByDeviceId(in *permission.DoTokenByDeviceIDReq) (*permission.Tokens, error) { - // todo: add your logic here and delete this line - - return &permission.Tokens{}, nil -} diff --git a/internal/logic/tokenservice/get_user_tokens_by_u_i_d_logic.go b/internal/logic/tokenservice/get_user_tokens_by_u_i_d_logic.go new file mode 100644 index 0000000..3ee5b08 --- /dev/null +++ b/internal/logic/tokenservice/get_user_tokens_by_u_i_d_logic.go @@ -0,0 +1,50 @@ +package tokenservicelogic + +import ( + "context" + + "code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/token" + + "code.30cm.net/digimon/app-cloudep-permission-server/gen_result/pb/permission" + "code.30cm.net/digimon/app-cloudep-permission-server/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type GetUserTokensByUIDLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewGetUserTokensByUIDLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserTokensByUIDLogic { + return &GetUserTokensByUIDLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// GetUserTokensByUid 取得目前所對應的 UID 所存在的 Tokens +func (l *GetUserTokensByUIDLogic) GetUserTokensByUID(in *permission.QueryTokenByUIDReq) (*permission.Tokens, error) { + uid, err := l.svcCtx.TokenUseCase.GetUserTokensByUID(l.ctx, in.GetUid()) + if err != nil { + return nil, err + } + + tokenType := token.Bearer + + result := make([]*permission.TokenResp, 0, len(uid)) + for _, v := range uid { + result = append(result, &permission.TokenResp{ + AccessToken: v.AccessToken, + ExpiresIn: v.ExpiresIn, + RefreshToken: v.RefreshToken, + TokenType: tokenType.ToString(), + }) + } + + return &permission.Tokens{ + Token: result, + }, nil +} diff --git a/internal/logic/tokenservice/get_user_tokens_by_uid_logic.go b/internal/logic/tokenservice/get_user_tokens_by_uid_logic.go deleted file mode 100644 index 1763389..0000000 --- a/internal/logic/tokenservice/get_user_tokens_by_uid_logic.go +++ /dev/null @@ -1,31 +0,0 @@ -package tokenservicelogic - -import ( - "context" - - "code.30cm.net/digimon/app-cloudep-permission-server/gen_result/pb/permission" - "code.30cm.net/digimon/app-cloudep-permission-server/internal/svc" - - "github.com/zeromicro/go-zero/core/logx" -) - -type GetUserTokensByUidLogic struct { - ctx context.Context - svcCtx *svc.ServiceContext - logx.Logger -} - -func NewGetUserTokensByUidLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserTokensByUidLogic { - return &GetUserTokensByUidLogic{ - ctx: ctx, - svcCtx: svcCtx, - Logger: logx.WithContext(ctx), - } -} - -// GetUserTokensByUid 取得目前所對應的 UID 所存在的 Tokens -func (l *GetUserTokensByUidLogic) GetUserTokensByUid(in *permission.QueryTokenByUIDReq) (*permission.Tokens, error) { - // todo: add your logic here and delete this line - - return &permission.Tokens{}, nil -} diff --git a/internal/logic/tokenservice/new_one_time_token_logic.go b/internal/logic/tokenservice/new_one_time_token_logic.go deleted file mode 100644 index 0cda13c..0000000 --- a/internal/logic/tokenservice/new_one_time_token_logic.go +++ /dev/null @@ -1,31 +0,0 @@ -package tokenservicelogic - -import ( - "context" - - "code.30cm.net/digimon/app-cloudep-permission-server/gen_result/pb/permission" - "code.30cm.net/digimon/app-cloudep-permission-server/internal/svc" - - "github.com/zeromicro/go-zero/core/logx" -) - -type NewOneTimeTokenLogic struct { - ctx context.Context - svcCtx *svc.ServiceContext - logx.Logger -} - -func NewNewOneTimeTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *NewOneTimeTokenLogic { - return &NewOneTimeTokenLogic{ - ctx: ctx, - svcCtx: svcCtx, - Logger: logx.WithContext(ctx), - } -} - -// NewOneTimeToken 建立一次性使用,例如:RefreshToken -func (l *NewOneTimeTokenLogic) NewOneTimeToken(in *permission.CreateOneTimeTokenReq) (*permission.CreateOneTimeTokenResp, error) { - // todo: add your logic here and delete this line - - return &permission.CreateOneTimeTokenResp{}, nil -} diff --git a/internal/logic/tokenservice/new_token_logic.go b/internal/logic/tokenservice/new_token_logic.go index 3ffad34..3a39629 100644 --- a/internal/logic/tokenservice/new_token_logic.go +++ b/internal/logic/tokenservice/new_token_logic.go @@ -2,9 +2,12 @@ package tokenservicelogic import ( "context" + "time" "code.30cm.net/digimon/app-cloudep-permission-server/gen_result/pb/permission" "code.30cm.net/digimon/app-cloudep-permission-server/internal/svc" + "code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/token" + "code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/usecase" "github.com/zeromicro/go-zero/core/logx" ) @@ -25,7 +28,42 @@ func NewNewTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *NewToken // NewToken 建立一個新的 Token,例如:AccessToken func (l *NewTokenLogic) NewToken(in *permission.AuthorizationReq) (*permission.TokenResp, error) { - // todo: add your logic here and delete this line + tokenType := token.Bearer + // TODO 要去拿 talbe + role := "user" - return &permission.TokenResp{}, nil + var expired, refreshExpired int64 + if in.GetExpires() > 0 { + expired = in.GetExpires() + } else { + expired = time.Now().UTC().Add(l.svcCtx.Config.Token.Expired).UnixNano() + } + + if in.GetRefreshExpire() > 0 { + refreshExpired = in.GetRefreshExpire() + } else { + refreshExpired = time.Now().UTC().Add(l.svcCtx.Config.Token.RefreshExpires).UnixNano() + } + + t, err := l.svcCtx.TokenUseCase.GenerateAccessToken(l.ctx, usecase.GenerateTokenRequest{ + TokenType: tokenType.ToString(), + DeviceID: in.GetDeviceId(), + Scope: in.GetScope(), + Expires: expired, + RefreshExpires: refreshExpired, + Role: role, + Account: in.GetAccount(), + UID: in.GetUid(), + Data: in.Data, + }) + if err != nil { + return nil, err + } + + return &permission.TokenResp{ + AccessToken: t.AccessToken, + RefreshToken: t.RefreshToken, + ExpiresIn: t.ExpiresIn, + TokenType: tokenType.ToString(), + }, nil } diff --git a/internal/logic/tokenservice/refresh_token_logic.go b/internal/logic/tokenservice/refresh_token_logic.go index fb9fef2..2b1e87d 100644 --- a/internal/logic/tokenservice/refresh_token_logic.go +++ b/internal/logic/tokenservice/refresh_token_logic.go @@ -2,6 +2,10 @@ package tokenservicelogic import ( "context" + "time" + + "code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/token" + "code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/usecase" "code.30cm.net/digimon/app-cloudep-permission-server/gen_result/pb/permission" "code.30cm.net/digimon/app-cloudep-permission-server/internal/svc" @@ -25,7 +29,31 @@ func NewRefreshTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Refr // RefreshToken 更新目前的token 以及裡面包含的一次性 Token func (l *RefreshTokenLogic) RefreshToken(in *permission.RefreshTokenReq) (*permission.RefreshTokenResp, error) { - // todo: add your logic here and delete this line + tokenType := token.Bearer + var expired int64 + if in.GetExpires() > 0 { + expired = in.GetExpires() + } else { + expired = time.Now().UTC().Add(l.svcCtx.Config.Token.Expired).UnixNano() + } - return &permission.RefreshTokenResp{}, nil + refreshExpired := time.Now().UTC().Add(l.svcCtx.Config.Token.RefreshExpires).UnixNano() + + t, err := l.svcCtx.TokenUseCase.RefreshAccessToken(l.ctx, usecase.RefreshTokenRequest{ + Token: in.GetToken(), // refresh token + Scope: in.GetScope(), + Expires: expired, + RefreshExpires: refreshExpired, + DeviceID: in.GetDeviceId(), + }) + if err != nil { + return nil, err + } + + return &permission.RefreshTokenResp{ + Token: t.AccessToken, + OneTimeToken: t.RefreshToken, + ExpiresIn: t.ExpiresIn, + TokenType: tokenType.ToString(), + }, nil } diff --git a/internal/logic/tokenservice/validation_token_logic.go b/internal/logic/tokenservice/validation_token_logic.go index e4f36c6..54edde8 100644 --- a/internal/logic/tokenservice/validation_token_logic.go +++ b/internal/logic/tokenservice/validation_token_logic.go @@ -5,6 +5,7 @@ import ( "code.30cm.net/digimon/app-cloudep-permission-server/gen_result/pb/permission" "code.30cm.net/digimon/app-cloudep-permission-server/internal/svc" + "code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/usecase" "github.com/zeromicro/go-zero/core/logx" ) @@ -25,7 +26,25 @@ func NewValidationTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *V // ValidationToken 驗證這個 Token 有沒有效 func (l *ValidationTokenLogic) ValidationToken(in *permission.ValidationTokenReq) (*permission.ValidationTokenResp, error) { - // todo: add your logic here and delete this line + token, err := l.svcCtx.TokenUseCase.VerifyToken(l.ctx, usecase.TokenRequest{ + Token: in.GetToken(), + }) + if err != nil { + return nil, err + } - return &permission.ValidationTokenResp{}, nil + return &permission.ValidationTokenResp{ + Token: &permission.Token{ + Id: token.Token.ID, + ClientId: 1, + DeviceId: token.Token.DeviceID, + AccessToken: token.Token.AccessToken, + ExpiresIn: token.Token.ExpiresIn, + AccessCreateAt: token.Token.AccessCreateAt, + RefreshToken: token.Token.RefreshToken, + RefreshExpiresIn: token.Token.RefreshExpiresIn, + RefreshCreateAt: token.Token.RefreshCreateAt, + }, + Data: token.Data, + }, nil } diff --git a/internal/server/tokenservice/token_service_server.go b/internal/server/tokenservice/token_service_server.go index e0a53ae..d19c253 100644 --- a/internal/server/tokenservice/token_service_server.go +++ b/internal/server/tokenservice/token_service_server.go @@ -7,9 +7,8 @@ package server import ( "context" - tokenservicelogic "code.30cm.net/digimon/app-cloudep-permission-server/internal/logic/tokenservice" - "code.30cm.net/digimon/app-cloudep-permission-server/gen_result/pb/permission" + tokenservicelogic "code.30cm.net/digimon/app-cloudep-permission-server/internal/logic/tokenservice" "code.30cm.net/digimon/app-cloudep-permission-server/internal/svc" ) @@ -54,32 +53,20 @@ func (s *TokenServiceServer) CancelTokens(ctx context.Context, in *permission.Do return l.CancelTokens(in) } -// CancelTokenByDeviceId 取消 Token, 從 Device 視角出發,可以選,登出這個Device 下所有 token ,登出這個Device 下指定token -func (s *TokenServiceServer) CancelTokenByDeviceId(ctx context.Context, in *permission.DoTokenByDeviceIDReq) (*permission.OKResp, error) { - l := tokenservicelogic.NewCancelTokenByDeviceIdLogic(ctx, s.svcCtx) - return l.CancelTokenByDeviceId(in) +// CancelTokenByDeviceID 取消 Token, 從 Device 視角出發,可以選,登出這個Device 下所有 token ,登出這個Device 下指定token +func (s *TokenServiceServer) CancelTokenByDeviceID(ctx context.Context, in *permission.DoTokenByDeviceIDReq) (*permission.OKResp, error) { + l := tokenservicelogic.NewCancelTokenByDeviceIDLogic(ctx, s.svcCtx) + return l.CancelTokenByDeviceID(in) } -// GetUserTokensByDeviceId 取得目前所對應的 DeviceID 所存在的 Tokens -func (s *TokenServiceServer) GetUserTokensByDeviceId(ctx context.Context, in *permission.DoTokenByDeviceIDReq) (*permission.Tokens, error) { - l := tokenservicelogic.NewGetUserTokensByDeviceIdLogic(ctx, s.svcCtx) - return l.GetUserTokensByDeviceId(in) +// GetUserTokensByDeviceID 取得目前所對應的 DeviceID 所存在的 Tokens +func (s *TokenServiceServer) GetUserTokensByDeviceID(ctx context.Context, in *permission.DoTokenByDeviceIDReq) (*permission.Tokens, error) { + l := tokenservicelogic.NewGetUserTokensByDeviceIDLogic(ctx, s.svcCtx) + return l.GetUserTokensByDeviceID(in) } -// GetUserTokensByUid 取得目前所對應的 UID 所存在的 Tokens -func (s *TokenServiceServer) GetUserTokensByUid(ctx context.Context, in *permission.QueryTokenByUIDReq) (*permission.Tokens, error) { - l := tokenservicelogic.NewGetUserTokensByUidLogic(ctx, s.svcCtx) - return l.GetUserTokensByUid(in) -} - -// NewOneTimeToken 建立一次性使用,例如:RefreshToken -func (s *TokenServiceServer) NewOneTimeToken(ctx context.Context, in *permission.CreateOneTimeTokenReq) (*permission.CreateOneTimeTokenResp, error) { - l := tokenservicelogic.NewNewOneTimeTokenLogic(ctx, s.svcCtx) - return l.NewOneTimeToken(in) -} - -// CancelOneTimeToken 取消一次性使用 -func (s *TokenServiceServer) CancelOneTimeToken(ctx context.Context, in *permission.CancelOneTimeTokenReq) (*permission.OKResp, error) { - l := tokenservicelogic.NewCancelOneTimeTokenLogic(ctx, s.svcCtx) - return l.CancelOneTimeToken(in) +// GetUserTokensByUID 取得目前所對應的 UID 所存在的 Tokens +func (s *TokenServiceServer) GetUserTokensByUID(ctx context.Context, in *permission.QueryTokenByUIDReq) (*permission.Tokens, error) { + l := tokenservicelogic.NewGetUserTokensByUIDLogic(ctx, s.svcCtx) + return l.GetUserTokensByUID(in) } diff --git a/internal/svc/service_context.go b/internal/svc/service_context.go index 1e77b14..11fddce 100644 --- a/internal/svc/service_context.go +++ b/internal/svc/service_context.go @@ -1,13 +1,32 @@ package svc -import "code.30cm.net/digimon/app-cloudep-permission-server/internal/config" +import ( + "code.30cm.net/digimon/app-cloudep-permission-server/internal/config" + duc "code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/usecase" + "code.30cm.net/digimon/app-cloudep-permission-server/pkg/repository" + "code.30cm.net/digimon/app-cloudep-permission-server/pkg/usecase" + "github.com/zeromicro/go-zero/core/stores/redis" +) type ServiceContext struct { - Config config.Config + Config config.Config + TokenUseCase duc.TokenUseCase } func NewServiceContext(c config.Config) *ServiceContext { + newRedis, err := redis.NewRedis(c.RedisCluster) + if err != nil { + panic(err) + } + repo := repository.NewTokenRepository(repository.TokenRepositoryParam{Redis: newRedis}) + return &ServiceContext{ Config: c, + TokenUseCase: usecase.NewTokenUseCase(usecase.TokenUseCaseParam{ + TokenRepo: repo, + RefreshExpires: c.Token.RefreshExpires, + Expired: c.Token.Expired, + Secret: c.Token.Secret, + }), } } diff --git a/pkg/domain/usecase/role_permission.go b/pkg/domain/usecase/role_permission.go index 46b3036..238b081 100644 --- a/pkg/domain/usecase/role_permission.go +++ b/pkg/domain/usecase/role_permission.go @@ -11,8 +11,8 @@ type RolePermissionUseCase interface { Create(ctx context.Context, roleID string, permissions permission.Permissions) error Delete(ctx context.Context, roleID string, permissions permission.Permissions) error List(ctx context.Context, req ListQuery) (RoleResp, error) - //GetByRoleUID(ctx context.Context, uid string) (permission.Permissions, error) - //GetByUser(ctx context.Context, uid string) (UserPermission, error) + // GetByRoleUID(ctx context.Context, uid string) (permission.Permissions, error) + // GetByUser(ctx context.Context, uid string) (UserPermission, error) } type UserPermission struct { diff --git a/pkg/mock/repository/role_permission.go b/pkg/mock/repository/role_permission.go index aa7860e..6acb35d 100644 --- a/pkg/mock/repository/role_permission.go +++ b/pkg/mock/repository/role_permission.go @@ -43,7 +43,7 @@ func (m *MockRolePermissionRepository) EXPECT() *MockRolePermissionRepositoryMoc } // Create mocks base method. -func (m *MockRolePermissionRepository) Create(ctx context.Context, entity entity.RolePermission) error { +func (m *MockRolePermissionRepository) Create(ctx context.Context, entity []entity.RolePermission) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Create", ctx, entity) ret0, _ := ret[0].(error) @@ -57,17 +57,17 @@ func (mr *MockRolePermissionRepositoryMockRecorder) Create(ctx, entity any) *gom } // Delete mocks base method. -func (m *MockRolePermissionRepository) Delete(ctx context.Context, roleID, permission string) error { +func (m *MockRolePermissionRepository) Delete(ctx context.Context, roleID string, permissions []string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Delete", ctx, roleID, permission) + ret := m.ctrl.Call(m, "Delete", ctx, roleID, permissions) ret0, _ := ret[0].(error) return ret0 } // Delete indicates an expected call of Delete. -func (mr *MockRolePermissionRepositoryMockRecorder) Delete(ctx, roleID, permission any) *gomock.Call { +func (mr *MockRolePermissionRepositoryMockRecorder) Delete(ctx, roleID, permissions any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockRolePermissionRepository)(nil).Delete), ctx, roleID, permission) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockRolePermissionRepository)(nil).Delete), ctx, roleID, permissions) } // Get mocks base method. diff --git a/pkg/repository/role_permission.go b/pkg/repository/role_permission.go index f723260..500bf4e 100644 --- a/pkg/repository/role_permission.go +++ b/pkg/repository/role_permission.go @@ -67,7 +67,7 @@ func (repo *RolePermissionRepository) Create(ctx context.Context, roles []entity now := time.Now().UTC().UnixNano() // 將 []entity.RolePermission 轉換為 []interface{} - var roleInterfaces []interface{} + roleInterfaces := make([]any, 0, len(roles)) for i := range roles { if roles[i].ID.IsZero() { roles[i].ID = primitive.NewObjectID() diff --git a/pkg/repository/token.go b/pkg/repository/token.go index 9eabb58..1d6c5cb 100644 --- a/pkg/repository/token.go +++ b/pkg/repository/token.go @@ -91,7 +91,6 @@ func (repo *TokenRepository) retrieveToken(ctx context.Context, key string) (ent if err != nil { return entity.Token{}, err } - if body == "" { return entity.Token{}, fmt.Errorf("failed to found token") } @@ -224,7 +223,16 @@ func (repo *TokenRepository) CreateOneTimeToken(ctx context.Context, key string, // GetAccessTokenByOneTimeToken 根據一次性 token 獲取 access token func (repo *TokenRepository) GetAccessTokenByOneTimeToken(ctx context.Context, oneTimeToken string) (entity.Token, error) { - return repo.retrieveToken(ctx, domain.GetRefreshTokenRedisKey(oneTimeToken)) + rk := domain.GetRefreshTokenRedisKey(oneTimeToken) + tokenID, err := repo.Redis.GetCtx(ctx, rk) + if err != nil { + return entity.Token{}, err + } + if tokenID == "" { + return entity.Token{}, fmt.Errorf("failed to found token") + } + + return repo.retrieveToken(ctx, domain.GetAccessTokenRedisKey(tokenID)) } // GetAccessTokenByID 根據 token ID 獲取 access token diff --git a/pkg/repository/token_test.go b/pkg/repository/token_test.go index 8612dc3..0e81d8b 100644 --- a/pkg/repository/token_test.go +++ b/pkg/repository/token_test.go @@ -890,7 +890,7 @@ func TestTokenRepository_GetAccessTokenByOneTimeToken(t *testing.T) { // 在 Redis 中設置模擬的數據 _ = mr.Set(domain.GetRefreshTokenRedisKey(oneTimeToken), accessTokenID) tokenData, _ := json.Marshal(expectedToken) - _ = mr.Set(domain.GetRefreshTokenRedisKey(oneTimeToken), string(tokenData)) + _ = mr.Set(domain.GetAccessTokenRedisKey(accessTokenID), string(tokenData)) // 定義測試場景 tests := []struct { diff --git a/pkg/repository/user_role_test.go b/pkg/repository/user_role_test.go index cdb365a..0dedba2 100644 --- a/pkg/repository/user_role_test.go +++ b/pkg/repository/user_role_test.go @@ -79,7 +79,6 @@ func TestUserRoleRepository_CreateUserRole(t *testing.T) { // 檢查資料是否真的被插入 var inserted entity.UserRole inserted, err = repo.GetByUserID(context.Background(), tc.input.UID) - fmt.Println(inserted) assert.NoError(t, err, "應該能找到插入的資料") assert.Equal(t, tc.input.UID, inserted.UID, "UID 應該匹配") assert.Equal(t, tc.input.RoleID, inserted.RoleID, "RoleID 應該匹配") @@ -263,7 +262,6 @@ func TestUserRoleRepository_GetUsersByRoleID(t *testing.T) { assert.Error(t, err, "應該返回錯誤") } else { assert.NoError(t, err, "不應該返回錯誤") - fmt.Println(result) compute := make([]entity.UserRole, 0, len(result)) res := make([]entity.UserRole, 0, len(result)) diff --git a/pkg/usecase/permission_tree.go b/pkg/usecase/permission_tree.go index ae3238a..3b09cbb 100644 --- a/pkg/usecase/permission_tree.go +++ b/pkg/usecase/permission_tree.go @@ -75,9 +75,11 @@ func GeneratePermissionTree(permissions []entity.Permission) *PermissionTree { func (tree *PermissionTree) getNode(id string) *PermissionNode { tree.mu.RLock() defer tree.mu.RUnlock() + return tree.nodes[id] } +//nolint:unused func (tree *PermissionTree) put(node entity.Permission) { parentNode := tree.getNode(node.Parent) if parentNode == nil { @@ -118,6 +120,7 @@ func (tree *PermissionTree) filterOpenNodes() (map[string]entity.Permission, err for _, child := range node.Children { dfs(child) } + return true } @@ -159,7 +162,6 @@ func (tree *PermissionTree) getFullParentPermission(rolePermissions []*entity.Ro status[parent.Data.Name] = permission.StatusCode(parent.Data.Status.String()) } - } return status @@ -213,7 +215,6 @@ func (tree *PermissionTree) getFullParentPermissionIDs(permissions permission.Pe exist[np.Data.ID.Hex()] = true } } - } } diff --git a/pkg/usecase/role_permission.go b/pkg/usecase/role_permission.go index 5a0c218..b91cae0 100644 --- a/pkg/usecase/role_permission.go +++ b/pkg/usecase/role_permission.go @@ -13,7 +13,7 @@ type RolePermissionUseCaseParam struct { rolePermissionRepository repository.RolePermissionRepository permissionRepository repository.PermissionRepository roleRepository repository.RoleRepository - userRoleRepository repository.UserRoleRepository + // userRoleRepository repository.UserRoleRepository } type RolePermissionUseCase struct { @@ -79,12 +79,8 @@ func (use *RolePermissionUseCase) Delete(ctx context.Context, roleID string, per if err != nil { return err } - del := make([]string, 0, len(permissions)) - for _, permissionID := range permissionIDs { - del = append(del, permissionID) - } - err = use.rolePermissionRepository.Delete(ctx, roleID, del) + err = use.rolePermissionRepository.Delete(ctx, roleID, permissionIDs) if err != nil { return err } @@ -121,49 +117,3 @@ func (use *RolePermissionUseCase) List(ctx context.Context, req usecase.ListQuer Roles: result, }, nil } - -//// GetByRoleUID 拿到這個 UID 底下有哪些權限是開的 -//func (use *RolePermissionUseCase) GetByRoleUID(ctx context.Context, uid string) (permission.Permissions, error) { -// permissions := make(permission.Permissions) -// -// // admin權限 -// if uid == permission.AdminRoleUID { -// data, err := use.permissionRepository.GetAll(ctx, nil) -// if err != nil { -// return nil, err -// } -// -// for _, v := range data { -// permissions[v.Name] = permission.OpenPermission -// } -// } else { -// role, err := use.roleRepository.GetByUID(ctx, uid) -// if err != nil { -// return nil, err -// } -// -// permissions, err = use.Get(ctx, role.ID.Hex()) -// if err != nil { -// return nil, err -// } -// } -// -// return permissions, nil -//} -// -//func (use *RolePermissionUseCase) GetByUser(ctx context.Context, uid string) (usecase.UserPermission, error) { -// userRole, err := use.userRoleRepository.GetByUserID(ctx, uid) -// if err != nil { -// return usecase.UserPermission{}, err -// } -// -// p, err := use.Get(ctx, userRole.RoleID) -// if err != nil { -// return usecase.UserPermission{}, err -// } -// -// return usecase.UserPermission{ -// RoleID: userRole.RoleID, -// Permissions: p, -// }, nil -//} diff --git a/pkg/usecase/token.go b/pkg/usecase/token.go index 60c1338..c4c581c 100644 --- a/pkg/usecase/token.go +++ b/pkg/usecase/token.go @@ -20,9 +20,9 @@ import ( type TokenUseCaseParam struct { TokenRepo repository.TokenRepo - RefreshExpires time.Duration - Expired time.Duration - Secret string + RefreshExpires time.Duration // refresh token 過期時間(比較長) + Expired time.Duration // token 過期時間(比較短) + Secret string // 加密Token } type TokenUseCase struct {