feat/create_new_token #2
|
@ -2,4 +2,5 @@
|
||||||
go.sum
|
go.sum
|
||||||
account/
|
account/
|
||||||
gen_result/
|
gen_result/
|
||||||
etc/permission.yaml
|
etc/permission.yaml
|
||||||
|
./client
|
|
@ -0,0 +1,45 @@
|
||||||
|
// Code generated by goctl. DO NOT EDIT.
|
||||||
|
// Source: permission.proto
|
||||||
|
|
||||||
|
package permissionservice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"ark-permission/gen_result/pb/permission"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/zrpc"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
AuthorizationReq = permission.AuthorizationReq
|
||||||
|
CancelOneTimeTokenReq = permission.CancelOneTimeTokenReq
|
||||||
|
CancelTokenReq = permission.CancelTokenReq
|
||||||
|
CreateOneTimeTokenReq = permission.CreateOneTimeTokenReq
|
||||||
|
CreateOneTimeTokenResp = permission.CreateOneTimeTokenResp
|
||||||
|
DoTokenByDeviceIDReq = permission.DoTokenByDeviceIDReq
|
||||||
|
DoTokenByUIDReq = permission.DoTokenByUIDReq
|
||||||
|
OKResp = permission.OKResp
|
||||||
|
QueryTokenByUIDReq = permission.QueryTokenByUIDReq
|
||||||
|
RefreshTokenReq = permission.RefreshTokenReq
|
||||||
|
RefreshTokenResp = permission.RefreshTokenResp
|
||||||
|
Token = permission.Token
|
||||||
|
TokenResp = permission.TokenResp
|
||||||
|
Tokens = permission.Tokens
|
||||||
|
ValidationTokenReq = permission.ValidationTokenReq
|
||||||
|
ValidationTokenResp = permission.ValidationTokenResp
|
||||||
|
|
||||||
|
PermissionService interface {
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultPermissionService struct {
|
||||||
|
cli zrpc.Client
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewPermissionService(cli zrpc.Client) PermissionService {
|
||||||
|
return &defaultPermissionService{
|
||||||
|
cli: cli,
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
// Code generated by goctl. DO NOT EDIT.
|
||||||
|
// Source: permission.proto
|
||||||
|
|
||||||
|
package roleservice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"ark-permission/gen_result/pb/permission"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/zrpc"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
AuthorizationReq = permission.AuthorizationReq
|
||||||
|
CancelOneTimeTokenReq = permission.CancelOneTimeTokenReq
|
||||||
|
CancelTokenReq = permission.CancelTokenReq
|
||||||
|
CreateOneTimeTokenReq = permission.CreateOneTimeTokenReq
|
||||||
|
CreateOneTimeTokenResp = permission.CreateOneTimeTokenResp
|
||||||
|
DoTokenByDeviceIDReq = permission.DoTokenByDeviceIDReq
|
||||||
|
DoTokenByUIDReq = permission.DoTokenByUIDReq
|
||||||
|
OKResp = permission.OKResp
|
||||||
|
QueryTokenByUIDReq = permission.QueryTokenByUIDReq
|
||||||
|
RefreshTokenReq = permission.RefreshTokenReq
|
||||||
|
RefreshTokenResp = permission.RefreshTokenResp
|
||||||
|
Token = permission.Token
|
||||||
|
TokenResp = permission.TokenResp
|
||||||
|
Tokens = permission.Tokens
|
||||||
|
ValidationTokenReq = permission.ValidationTokenReq
|
||||||
|
ValidationTokenResp = permission.ValidationTokenResp
|
||||||
|
|
||||||
|
RoleService interface {
|
||||||
|
Ping(ctx context.Context, in *OKResp, opts ...grpc.CallOption) (*OKResp, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultRoleService struct {
|
||||||
|
cli zrpc.Client
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewRoleService(cli zrpc.Client) RoleService {
|
||||||
|
return &defaultRoleService{
|
||||||
|
cli: cli,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *defaultRoleService) Ping(ctx context.Context, in *OKResp, opts ...grpc.CallOption) (*OKResp, error) {
|
||||||
|
client := permission.NewRoleServiceClient(m.cli.Conn())
|
||||||
|
return client.Ping(ctx, in, opts...)
|
||||||
|
}
|
|
@ -14,12 +14,14 @@ import (
|
||||||
|
|
||||||
type (
|
type (
|
||||||
AuthorizationReq = permission.AuthorizationReq
|
AuthorizationReq = permission.AuthorizationReq
|
||||||
|
CancelOneTimeTokenReq = permission.CancelOneTimeTokenReq
|
||||||
CancelTokenReq = permission.CancelTokenReq
|
CancelTokenReq = permission.CancelTokenReq
|
||||||
CreateOneTimeTokenReq = permission.CreateOneTimeTokenReq
|
CreateOneTimeTokenReq = permission.CreateOneTimeTokenReq
|
||||||
CreateOneTimeTokenResp = permission.CreateOneTimeTokenResp
|
CreateOneTimeTokenResp = permission.CreateOneTimeTokenResp
|
||||||
DoTokenByDeviceIDReq = permission.DoTokenByDeviceIDReq
|
DoTokenByDeviceIDReq = permission.DoTokenByDeviceIDReq
|
||||||
DoTokenByUIDReq = permission.DoTokenByUIDReq
|
DoTokenByUIDReq = permission.DoTokenByUIDReq
|
||||||
OKResp = permission.OKResp
|
OKResp = permission.OKResp
|
||||||
|
QueryTokenByUIDReq = permission.QueryTokenByUIDReq
|
||||||
RefreshTokenReq = permission.RefreshTokenReq
|
RefreshTokenReq = permission.RefreshTokenReq
|
||||||
RefreshTokenResp = permission.RefreshTokenResp
|
RefreshTokenResp = permission.RefreshTokenResp
|
||||||
Token = permission.Token
|
Token = permission.Token
|
||||||
|
@ -35,20 +37,20 @@ type (
|
||||||
RefreshToken(ctx context.Context, in *RefreshTokenReq, opts ...grpc.CallOption) (*RefreshTokenResp, error)
|
RefreshToken(ctx context.Context, in *RefreshTokenReq, opts ...grpc.CallOption) (*RefreshTokenResp, error)
|
||||||
// CancelToken 取消 Token,也包含他裡面的 One Time Toke
|
// CancelToken 取消 Token,也包含他裡面的 One Time Toke
|
||||||
CancelToken(ctx context.Context, in *CancelTokenReq, opts ...grpc.CallOption) (*OKResp, error)
|
CancelToken(ctx context.Context, in *CancelTokenReq, opts ...grpc.CallOption) (*OKResp, error)
|
||||||
// CancelTokenByUID 取消 Token (取消這個用戶從不同 Device 登入的所有 Token),也包含他裡面的 One Time Toke
|
|
||||||
CancelTokenByUID(ctx context.Context, in *DoTokenByUIDReq, opts ...grpc.CallOption) (*OKResp, error)
|
|
||||||
// CancelTokenByDeviceID 取消 Token
|
|
||||||
CancelTokenByDeviceID(ctx context.Context, in *DoTokenByDeviceIDReq, opts ...grpc.CallOption) (*OKResp, error)
|
|
||||||
// ValidationToken 驗證這個 Token 有沒有效
|
// ValidationToken 驗證這個 Token 有沒有效
|
||||||
ValidationToken(ctx context.Context, in *ValidationTokenReq, opts ...grpc.CallOption) (*ValidationTokenResp, error)
|
ValidationToken(ctx context.Context, in *ValidationTokenReq, opts ...grpc.CallOption) (*ValidationTokenResp, error)
|
||||||
// GetUserTokensByDeviceIDs 取得目前所對應的 DeviceID 所存在的 Tokens
|
// CancelTokens 取消 Token 從UID 視角,以及 token id 視角出發, UID 登出,底下所有 Device ID 也要登出, Token ID 登出, 所有 UID + Device 都要登出
|
||||||
GetUserTokensByDeviceID(ctx context.Context, in *DoTokenByDeviceIDReq, opts ...grpc.CallOption) (*Tokens, error)
|
CancelTokens(ctx context.Context, in *DoTokenByUIDReq, opts ...grpc.CallOption) (*OKResp, error)
|
||||||
// GetUserTokensByUID 取得目前所對應的 UID 所存在的 Tokens
|
// CancelTokenByDeviceId 取消 Token, 從 Device 視角出發,可以選,登出這個Device 下所有 token ,登出這個Device 下指定token
|
||||||
GetUserTokensByUID(ctx context.Context, in *DoTokenByUIDReq, opts ...grpc.CallOption) (*Tokens, error)
|
CancelTokenByDeviceId(ctx context.Context, in *DoTokenByDeviceIDReq, opts ...grpc.CallOption) (*OKResp, error)
|
||||||
|
// GetUserTokensByDeviceId 取得目前所對應的 DeviceID 所存在的 Tokens
|
||||||
|
GetUserTokensByDeviceId(ctx context.Context, in *DoTokenByDeviceIDReq, opts ...grpc.CallOption) (*Tokens, error)
|
||||||
|
// GetUserTokensByUid 取得目前所對應的 UID 所存在的 Tokens
|
||||||
|
GetUserTokensByUid(ctx context.Context, in *QueryTokenByUIDReq, opts ...grpc.CallOption) (*Tokens, error)
|
||||||
// NewOneTimeToken 建立一次性使用,例如:RefreshToken
|
// NewOneTimeToken 建立一次性使用,例如:RefreshToken
|
||||||
NewOneTimeToken(ctx context.Context, in *CreateOneTimeTokenReq, opts ...grpc.CallOption) (*CreateOneTimeTokenResp, error)
|
NewOneTimeToken(ctx context.Context, in *CreateOneTimeTokenReq, opts ...grpc.CallOption) (*CreateOneTimeTokenResp, error)
|
||||||
// CancelOneTimeToken 取消一次性使用
|
// CancelOneTimeToken 取消一次性使用
|
||||||
CancelOneTimeToken(ctx context.Context, in *CreateOneTimeTokenReq, opts ...grpc.CallOption) (*CreateOneTimeTokenResp, error)
|
CancelOneTimeToken(ctx context.Context, in *CancelOneTimeTokenReq, opts ...grpc.CallOption) (*OKResp, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultTokenService struct {
|
defaultTokenService struct {
|
||||||
|
@ -80,34 +82,34 @@ func (m *defaultTokenService) CancelToken(ctx context.Context, in *CancelTokenRe
|
||||||
return client.CancelToken(ctx, in, opts...)
|
return client.CancelToken(ctx, in, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CancelTokenByUID 取消 Token (取消這個用戶從不同 Device 登入的所有 Token),也包含他裡面的 One Time Toke
|
|
||||||
func (m *defaultTokenService) CancelTokenByUID(ctx context.Context, in *DoTokenByUIDReq, opts ...grpc.CallOption) (*OKResp, error) {
|
|
||||||
client := permission.NewTokenServiceClient(m.cli.Conn())
|
|
||||||
return client.CancelTokenByUID(ctx, in, opts...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CancelTokenByDeviceID 取消 Token
|
|
||||||
func (m *defaultTokenService) CancelTokenByDeviceID(ctx context.Context, in *DoTokenByDeviceIDReq, opts ...grpc.CallOption) (*OKResp, error) {
|
|
||||||
client := permission.NewTokenServiceClient(m.cli.Conn())
|
|
||||||
return client.CancelTokenByDeviceID(ctx, in, opts...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidationToken 驗證這個 Token 有沒有效
|
// ValidationToken 驗證這個 Token 有沒有效
|
||||||
func (m *defaultTokenService) ValidationToken(ctx context.Context, in *ValidationTokenReq, opts ...grpc.CallOption) (*ValidationTokenResp, error) {
|
func (m *defaultTokenService) ValidationToken(ctx context.Context, in *ValidationTokenReq, opts ...grpc.CallOption) (*ValidationTokenResp, error) {
|
||||||
client := permission.NewTokenServiceClient(m.cli.Conn())
|
client := permission.NewTokenServiceClient(m.cli.Conn())
|
||||||
return client.ValidationToken(ctx, in, opts...)
|
return client.ValidationToken(ctx, in, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserTokensByDeviceIDs 取得目前所對應的 DeviceID 所存在的 Tokens
|
// CancelTokens 取消 Token 從UID 視角,以及 token id 視角出發, UID 登出,底下所有 Device ID 也要登出, Token ID 登出, 所有 UID + Device 都要登出
|
||||||
func (m *defaultTokenService) GetUserTokensByDeviceID(ctx context.Context, in *DoTokenByDeviceIDReq, opts ...grpc.CallOption) (*Tokens, error) {
|
func (m *defaultTokenService) CancelTokens(ctx context.Context, in *DoTokenByUIDReq, opts ...grpc.CallOption) (*OKResp, error) {
|
||||||
client := permission.NewTokenServiceClient(m.cli.Conn())
|
client := permission.NewTokenServiceClient(m.cli.Conn())
|
||||||
return client.GetUserTokensByDeviceID(ctx, in, opts...)
|
return client.CancelTokens(ctx, in, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserTokensByUID 取得目前所對應的 UID 所存在的 Tokens
|
// CancelTokenByDeviceId 取消 Token, 從 Device 視角出發,可以選,登出這個Device 下所有 token ,登出這個Device 下指定token
|
||||||
func (m *defaultTokenService) GetUserTokensByUID(ctx context.Context, in *DoTokenByUIDReq, opts ...grpc.CallOption) (*Tokens, error) {
|
func (m *defaultTokenService) CancelTokenByDeviceId(ctx context.Context, in *DoTokenByDeviceIDReq, opts ...grpc.CallOption) (*OKResp, error) {
|
||||||
client := permission.NewTokenServiceClient(m.cli.Conn())
|
client := permission.NewTokenServiceClient(m.cli.Conn())
|
||||||
return client.GetUserTokensByUID(ctx, in, opts...)
|
return client.CancelTokenByDeviceId(ctx, in, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserTokensByDeviceId 取得目前所對應的 DeviceID 所存在的 Tokens
|
||||||
|
func (m *defaultTokenService) GetUserTokensByDeviceId(ctx context.Context, in *DoTokenByDeviceIDReq, opts ...grpc.CallOption) (*Tokens, error) {
|
||||||
|
client := permission.NewTokenServiceClient(m.cli.Conn())
|
||||||
|
return client.GetUserTokensByDeviceId(ctx, in, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserTokensByUid 取得目前所對應的 UID 所存在的 Tokens
|
||||||
|
func (m *defaultTokenService) GetUserTokensByUid(ctx context.Context, in *QueryTokenByUIDReq, opts ...grpc.CallOption) (*Tokens, error) {
|
||||||
|
client := permission.NewTokenServiceClient(m.cli.Conn())
|
||||||
|
return client.GetUserTokensByUid(ctx, in, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOneTimeToken 建立一次性使用,例如:RefreshToken
|
// NewOneTimeToken 建立一次性使用,例如:RefreshToken
|
||||||
|
@ -117,7 +119,7 @@ func (m *defaultTokenService) NewOneTimeToken(ctx context.Context, in *CreateOne
|
||||||
}
|
}
|
||||||
|
|
||||||
// CancelOneTimeToken 取消一次性使用
|
// CancelOneTimeToken 取消一次性使用
|
||||||
func (m *defaultTokenService) CancelOneTimeToken(ctx context.Context, in *CreateOneTimeTokenReq, opts ...grpc.CallOption) (*CreateOneTimeTokenResp, error) {
|
func (m *defaultTokenService) CancelOneTimeToken(ctx context.Context, in *CancelOneTimeTokenReq, opts ...grpc.CallOption) (*OKResp, error) {
|
||||||
client := permission.NewTokenServiceClient(m.cli.Conn())
|
client := permission.NewTokenServiceClient(m.cli.Conn())
|
||||||
return client.CancelOneTimeToken(ctx, in, opts...)
|
return client.CancelOneTimeToken(ctx, in, opts...)
|
||||||
}
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
Name: permission.rpc
|
||||||
|
ListenOn: 0.0.0.0:8080
|
||||||
|
Etcd:
|
||||||
|
Hosts:
|
||||||
|
- 127.0.0.1:2379
|
||||||
|
Key: permission.rpc
|
||||||
|
|
||||||
|
RedisCluster:
|
||||||
|
Host: 127.0.0.1:7001
|
||||||
|
Type: cluster
|
||||||
|
|
||||||
|
Token:
|
||||||
|
Expired: 300
|
||||||
|
RefreshExpires: 86500
|
||||||
|
Secret: gg88g88
|
|
@ -1 +1 @@
|
||||||
DROP DATABASE IF EXISTS `ark_member`;
|
DROP DATABASE IF EXISTS `ark_permission`;
|
|
@ -1 +1 @@
|
||||||
CREATE DATABASE IF NOT EXISTS `ark_member`;
|
CREATE DATABASE IF NOT EXISTS `ark_permission`;
|
|
@ -68,7 +68,13 @@ message CancelTokenReq {
|
||||||
|
|
||||||
// CancelTokenReq 註銷這個 Token
|
// CancelTokenReq 註銷這個 Token
|
||||||
message DoTokenByUIDReq {
|
message DoTokenByUIDReq {
|
||||||
repeated string uid = 1;
|
repeated string ids = 1;
|
||||||
|
string uid = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryTokenByUIDReq 拿這個UID 找 Token
|
||||||
|
message QueryTokenByUIDReq {
|
||||||
|
string uid = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidationTokenReq 驗證這個 Token
|
// ValidationTokenReq 驗證這個 Token
|
||||||
|
@ -108,10 +114,14 @@ message Token {
|
||||||
|
|
||||||
// DoTokenByDeviceIDReq 用DeviceID 來做事的
|
// DoTokenByDeviceIDReq 用DeviceID 來做事的
|
||||||
message DoTokenByDeviceIDReq {
|
message DoTokenByDeviceIDReq {
|
||||||
repeated string device_id = 1;
|
string device_id = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Tokens{
|
message Tokens{
|
||||||
|
repeated TokenResp token = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CancelOneTimeTokenReq {
|
||||||
repeated string token = 1;
|
repeated string token = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,23 +135,29 @@ service TokenService {
|
||||||
rpc RefreshToken(RefreshTokenReq) returns(RefreshTokenResp);
|
rpc RefreshToken(RefreshTokenReq) returns(RefreshTokenResp);
|
||||||
// CancelToken 取消 Token,也包含他裡面的 One Time Toke
|
// CancelToken 取消 Token,也包含他裡面的 One Time Toke
|
||||||
rpc CancelToken(CancelTokenReq) returns(OKResp);
|
rpc CancelToken(CancelTokenReq) returns(OKResp);
|
||||||
// CancelTokenByUID 取消 Token (取消這個用戶從不同 Device 登入的所有 Token),也包含他裡面的 One Time Toke
|
|
||||||
rpc CancelTokenByUID(DoTokenByUIDReq) returns(OKResp);
|
|
||||||
// CancelTokenByDeviceID 取消 Token
|
|
||||||
rpc CancelTokenByDeviceID(DoTokenByDeviceIDReq) returns(OKResp);
|
|
||||||
// ValidationToken 驗證這個 Token 有沒有效
|
// ValidationToken 驗證這個 Token 有沒有效
|
||||||
rpc ValidationToken(ValidationTokenReq) returns(ValidationTokenResp);
|
rpc ValidationToken(ValidationTokenReq) returns(ValidationTokenResp);
|
||||||
// GetUserTokensByDeviceIDs 取得目前所對應的 DeviceID 所存在的 Tokens
|
// CancelTokens 取消 Token 從UID 視角,以及 token id 視角出發, UID 登出,底下所有 Device ID 也要登出, Token ID 登出, 所有 UID + Device 都要登出
|
||||||
rpc GetUserTokensByDeviceID(DoTokenByDeviceIDReq) returns(Tokens);
|
rpc CancelTokens(DoTokenByUIDReq) returns(OKResp);
|
||||||
// GetUserTokensByUID 取得目前所對應的 UID 所存在的 Tokens
|
|
||||||
rpc GetUserTokensByUID(DoTokenByUIDReq) returns(Tokens);
|
// 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
|
// NewOneTimeToken 建立一次性使用,例如:RefreshToken
|
||||||
rpc NewOneTimeToken(CreateOneTimeTokenReq) returns(CreateOneTimeTokenResp);
|
rpc NewOneTimeToken(CreateOneTimeTokenReq) returns(CreateOneTimeTokenResp);
|
||||||
// CancelOneTimeToken 取消一次性使用
|
// CancelOneTimeToken 取消一次性使用
|
||||||
rpc CancelOneTimeToken(CreateOneTimeTokenReq) returns(CreateOneTimeTokenResp);
|
rpc CancelOneTimeToken(CancelOneTimeTokenReq) returns(OKResp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//service Role_Service {}
|
service RoleService {
|
||||||
//
|
rpc Ping(OKResp) returns(OKResp);
|
||||||
//service Permission_Service {}
|
}
|
||||||
|
|
||||||
|
service PermissionService {}
|
11
go.mod
11
go.mod
|
@ -3,7 +3,12 @@ module ark-permission
|
||||||
go 1.22.3
|
go 1.22.3
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
code.30cm.net/wanderland/library-go/errors v1.0.1
|
||||||
|
github.com/go-playground/validator/v10 v10.22.0
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||||
|
github.com/google/uuid v1.6.0
|
||||||
github.com/zeromicro/go-zero v1.7.0
|
github.com/zeromicro/go-zero v1.7.0
|
||||||
|
go.uber.org/mock v0.4.0
|
||||||
google.golang.org/grpc v1.65.0
|
google.golang.org/grpc v1.65.0
|
||||||
google.golang.org/protobuf v1.34.2
|
google.golang.org/protobuf v1.34.2
|
||||||
)
|
)
|
||||||
|
@ -18,21 +23,24 @@ require (
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||||
github.com/fatih/color v1.17.0 // indirect
|
github.com/fatih/color v1.17.0 // indirect
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||||
github.com/go-logr/logr v1.4.2 // indirect
|
github.com/go-logr/logr v1.4.2 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||||
github.com/go-openapi/swag v0.22.4 // indirect
|
github.com/go-openapi/swag v0.22.4 // indirect
|
||||||
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang/mock v1.6.0 // indirect
|
github.com/golang/mock v1.6.0 // indirect
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/google/gnostic-models v0.6.8 // indirect
|
github.com/google/gnostic-models v0.6.8 // indirect
|
||||||
github.com/google/go-cmp v0.6.0 // indirect
|
github.com/google/go-cmp v0.6.0 // indirect
|
||||||
github.com/google/gofuzz v1.2.0 // indirect
|
github.com/google/gofuzz v1.2.0 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
@ -65,6 +73,7 @@ require (
|
||||||
go.uber.org/automaxprocs v1.5.3 // indirect
|
go.uber.org/automaxprocs v1.5.3 // indirect
|
||||||
go.uber.org/multierr v1.9.0 // indirect
|
go.uber.org/multierr v1.9.0 // indirect
|
||||||
go.uber.org/zap v1.24.0 // indirect
|
go.uber.org/zap v1.24.0 // indirect
|
||||||
|
golang.org/x/crypto v0.25.0 // indirect
|
||||||
golang.org/x/net v0.27.0 // indirect
|
golang.org/x/net v0.27.0 // indirect
|
||||||
golang.org/x/oauth2 v0.20.0 // indirect
|
golang.org/x/oauth2 v0.20.0 // indirect
|
||||||
golang.org/x/sys v0.22.0 // indirect
|
golang.org/x/sys v0.22.0 // indirect
|
||||||
|
|
|
@ -1,7 +1,17 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import "github.com/zeromicro/go-zero/zrpc"
|
import (
|
||||||
|
"github.com/zeromicro/go-zero/core/stores/redis"
|
||||||
|
"github.com/zeromicro/go-zero/zrpc"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
zrpc.RpcServerConf
|
zrpc.RpcServerConf
|
||||||
|
RedisCluster redis.RedisConf
|
||||||
|
Token struct {
|
||||||
|
RefreshExpires time.Duration
|
||||||
|
Expired time.Duration
|
||||||
|
Secret string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package domain
|
||||||
|
|
||||||
|
type GrantType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
PasswordCredentials GrantType = "password"
|
||||||
|
ClientCredentials GrantType = "client_credentials"
|
||||||
|
Refreshing GrantType = "refresh_token"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultRole 預設role
|
||||||
|
DefaultRole = "user"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
TokenTypeBearer = "Bearer"
|
||||||
|
)
|
|
@ -0,0 +1,65 @@
|
||||||
|
package domain
|
||||||
|
|
||||||
|
import (
|
||||||
|
mts "ark-permission/internal/lib/metric"
|
||||||
|
|
||||||
|
ers "code.30cm.net/wanderland/library-go/errors"
|
||||||
|
"code.30cm.net/wanderland/library-go/errors/code"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 12 represents Scope
|
||||||
|
// 100 represents Category
|
||||||
|
// 9 represents Detail error code
|
||||||
|
// full code 12009 只會有 系統以及錯誤碼,category 是給系統判定用的
|
||||||
|
// 目前 Scope 以及分類要系統共用,係向的錯誤各自服務實作就好
|
||||||
|
|
||||||
|
const (
|
||||||
|
TokenUnexpectedSigningErrorCode = iota + 1
|
||||||
|
TokenValidateErrorCode
|
||||||
|
TokenClaimErrorCode
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
RedisDelErrorCode = iota + 20
|
||||||
|
RedisPipLineErrorCode
|
||||||
|
RedisErrorCode
|
||||||
|
)
|
||||||
|
|
||||||
|
// TokenUnexpectedSigningErr 30001 Token 簽名錯誤
|
||||||
|
func TokenUnexpectedSigningErr(msg string) *ers.Err {
|
||||||
|
mts.AppErrorMetrics.AddFailure("token", "token_unexpected_sign")
|
||||||
|
return ers.NewErr(code.CloudEPPermission, code.CatInput, TokenUnexpectedSigningErrorCode, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenTokenValidateErr 30002 Token 驗證錯誤
|
||||||
|
func TokenTokenValidateErr(msg string) *ers.Err {
|
||||||
|
mts.AppErrorMetrics.AddFailure("token", "token_validate_ilegal")
|
||||||
|
return ers.NewErr(code.CloudEPPermission, code.CatInput, TokenValidateErrorCode, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenClaimError 30003 Token 驗證錯誤
|
||||||
|
func TokenClaimError(msg string) *ers.Err {
|
||||||
|
mts.AppErrorMetrics.AddFailure("token", "token_claim_error")
|
||||||
|
return ers.NewErr(code.CloudEPPermission, code.CatInput, TokenClaimErrorCode, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RedisDelError 30020 Redis 刪除錯誤
|
||||||
|
func RedisDelError(msg string) *ers.Err {
|
||||||
|
// 看需要建立哪些 Metrics
|
||||||
|
mts.AppErrorMetrics.AddFailure("redis", "del_error")
|
||||||
|
return ers.NewErr(code.CloudEPPermission, code.CatDB, RedisDelErrorCode, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RedisPipLineError 30021 Redis PipLine 錯誤
|
||||||
|
func RedisPipLineError(msg string) *ers.Err {
|
||||||
|
// 看需要建立哪些 Metrics
|
||||||
|
mts.AppErrorMetrics.AddFailure("redis", "pip_line_error")
|
||||||
|
return ers.NewErr(code.CloudEPPermission, code.CatInput, RedisPipLineErrorCode, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RedisError 30022 Redis 錯誤
|
||||||
|
func RedisError(msg string) *ers.Err {
|
||||||
|
// 看需要建立哪些 Metrics
|
||||||
|
mts.AppErrorMetrics.AddFailure("redis", "error")
|
||||||
|
return ers.NewErr(code.CloudEPPermission, code.CatInput, RedisErrorCode, msg)
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package domain
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
const (
|
||||||
|
TicketKeyPrefix = "tic/"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ClientDataKey = "permission:clients"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RedisKey string
|
||||||
|
|
||||||
|
const (
|
||||||
|
AccessTokenRedisKey RedisKey = "access_token"
|
||||||
|
RefreshTokenRedisKey RedisKey = "refresh_token"
|
||||||
|
DeviceTokenRedisKey RedisKey = "device_token"
|
||||||
|
UIDTokenRedisKey RedisKey = "uid_token"
|
||||||
|
TicketRedisKey RedisKey = "ticket"
|
||||||
|
DeviceUIDRedisKey RedisKey = "device_uid"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (key RedisKey) ToString() string {
|
||||||
|
return "permission:" + string(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (key RedisKey) With(s ...string) RedisKey {
|
||||||
|
parts := append([]string{string(key)}, s...)
|
||||||
|
|
||||||
|
return RedisKey(strings.Join(parts, ":"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAccessTokenRedisKey(id string) string {
|
||||||
|
return AccessTokenRedisKey.With(id).ToString()
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetUIDTokenRedisKey(uid string) string {
|
||||||
|
return UIDTokenRedisKey.With(uid).ToString()
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTicketRedisKey(ticket string) string {
|
||||||
|
return TicketRedisKey.With(ticket).ToString()
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ark-permission/internal/entity"
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TokenRepository token 的 redis 操作
|
||||||
|
type TokenRepository interface {
|
||||||
|
// Create 建立Token
|
||||||
|
Create(ctx context.Context, token entity.Token) error
|
||||||
|
// CreateOneTimeToken 建立臨時 Token
|
||||||
|
CreateOneTimeToken(ctx context.Context, key string, ticket entity.Ticket, dt time.Duration) error
|
||||||
|
|
||||||
|
GetAccessTokenByByOneTimeToken(ctx context.Context, oneTimeToken string) (entity.Token, error)
|
||||||
|
GetAccessTokenByID(ctx context.Context, id string) (entity.Token, error)
|
||||||
|
GetAccessTokensByUID(ctx context.Context, uid string) ([]entity.Token, error)
|
||||||
|
GetAccessTokenCountByUID(uid string) (int, error)
|
||||||
|
GetAccessTokensByDeviceID(ctx context.Context, deviceID string) ([]entity.Token, error)
|
||||||
|
GetAccessTokenCountByDeviceID(deviceID string) (int, error)
|
||||||
|
|
||||||
|
Delete(ctx context.Context, token entity.Token) error
|
||||||
|
DeleteOneTimeToken(ctx context.Context, ids []string, tokens []entity.Token) error
|
||||||
|
DeleteAccessTokenByID(ctx context.Context, ids []string) error
|
||||||
|
DeleteAccessTokensByUID(ctx context.Context, uid string) error
|
||||||
|
DeleteAccessTokensByDeviceID(ctx context.Context, deviceID string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeviceToken struct {
|
||||||
|
DeviceID string
|
||||||
|
TokenID string
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package entity
|
||||||
|
|
||||||
|
import "github.com/golang-jwt/jwt/v4"
|
||||||
|
|
||||||
|
type Claims struct {
|
||||||
|
jwt.RegisteredClaims
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package entity
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type Token struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
UID string `json:"uid"`
|
||||||
|
DeviceID string `json:"device_id"`
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
ExpiresIn int `json:"expires_in"`
|
||||||
|
AccessCreateAt time.Time `json:"access_create_at"`
|
||||||
|
RefreshToken string `json:"refresh_token"`
|
||||||
|
RefreshExpiresIn int `json:"refresh_expires_in"`
|
||||||
|
RefreshCreateAt time.Time `json:"refresh_create_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Token) AccessTokenExpires() time.Duration {
|
||||||
|
return time.Duration(t.ExpiresIn) * time.Second
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Token) RefreshTokenExpires() time.Duration {
|
||||||
|
return time.Duration(t.RefreshExpiresIn) * time.Second
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Token) RefreshTokenExpiresUnix() int64 {
|
||||||
|
return time.Now().Add(t.RefreshTokenExpires()).Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Token) IsExpires() bool {
|
||||||
|
return t.AccessCreateAt.Add(t.AccessTokenExpires()).Before(time.Now())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Token) RedisExpiredSec() int64 {
|
||||||
|
sec := time.Unix(int64(t.ExpiresIn), 0).Sub(time.Now().UTC())
|
||||||
|
|
||||||
|
return int64(sec.Seconds())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Token) RedisRefreshExpiredSec() int64 {
|
||||||
|
sec := time.Unix(int64(t.RefreshExpiresIn), 0).Sub(time.Now().UTC())
|
||||||
|
|
||||||
|
return int64(sec.Seconds())
|
||||||
|
}
|
||||||
|
|
||||||
|
type UIDToken map[string]int64
|
||||||
|
|
||||||
|
type Ticket struct {
|
||||||
|
Data any `json:"data"`
|
||||||
|
Token Token `json:"token"`
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package metric
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/zeromicro/go-zero/core/metric"
|
||||||
|
)
|
||||||
|
|
||||||
|
var AppErrorMetrics = NewAppErrMetrics()
|
||||||
|
|
||||||
|
type appErrMetrics struct {
|
||||||
|
metric.CounterVec
|
||||||
|
}
|
||||||
|
|
||||||
|
type Metrics interface {
|
||||||
|
AddFailure(source, reason string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAppErrMetrics initiate metrics and register to prometheus
|
||||||
|
func NewAppErrMetrics() Metrics {
|
||||||
|
return &appErrMetrics{metric.NewCounterVec(&metric.CounterVecOpts{
|
||||||
|
Namespace: "ark",
|
||||||
|
Subsystem: "permission",
|
||||||
|
Name: "permission_app_error_total",
|
||||||
|
Help: "App defined failure total.",
|
||||||
|
Labels: []string{"source", "reason"},
|
||||||
|
})}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *appErrMetrics) AddFailure(source, reason string) {
|
||||||
|
m.Inc(source, reason)
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
package metric
|
|
@ -0,0 +1,28 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
ers "ark-permission/internal/lib/error"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultTimeout = 30 * time.Second
|
||||||
|
|
||||||
|
func TimeoutMiddleware(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) {
|
||||||
|
|
||||||
|
newCtx, cancelCtx := context.WithTimeout(ctx, defaultTimeout)
|
||||||
|
defer func() {
|
||||||
|
cancelCtx()
|
||||||
|
|
||||||
|
if errors.Is(newCtx.Err(), context.DeadlineExceeded) {
|
||||||
|
err = ers.SystemTimeoutError(info.FullMethod)
|
||||||
|
logx.Errorf("Method: %s, request %v, timeout: %d", info.FullMethod, req, defaultTimeout)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return handler(ctx, req)
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package required
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Validate interface {
|
||||||
|
ValidateAll(obj any) error
|
||||||
|
BindToValidator(opts ...Option) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type Validator struct {
|
||||||
|
V *validator.Validate
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateAll TODO 要移到common 包
|
||||||
|
func (v *Validator) ValidateAll(obj any) error {
|
||||||
|
err := v.V.Struct(obj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Validator) BindToValidator(opts ...Option) error {
|
||||||
|
for _, item := range opts {
|
||||||
|
err := v.V.RegisterValidation(item.ValidatorName, item.ValidatorFunc)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to register validator : %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func MustValidator(option ...Option) Validate {
|
||||||
|
v := &Validator{
|
||||||
|
V: validator.New(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := v.BindToValidator(option...); err != nil {
|
||||||
|
logx.Error("failed to bind validator")
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package required
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Option struct {
|
||||||
|
ValidatorName string
|
||||||
|
ValidatorFunc func(fl validator.FieldLevel) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithAccount 創建一個新的 Option 結構,包含自定義的驗證函數,用於驗證 email 和台灣的手機號碼格式
|
||||||
|
func WithAccount(tagName string) Option {
|
||||||
|
return Option{
|
||||||
|
ValidatorName: tagName,
|
||||||
|
ValidatorFunc: func(fl validator.FieldLevel) bool {
|
||||||
|
value := fl.Field().String()
|
||||||
|
emailRegex := `^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}$`
|
||||||
|
phoneRegex := `^(\+886|0)?9\d{8}$`
|
||||||
|
|
||||||
|
emailMatch, _ := regexp.MatchString(emailRegex, value)
|
||||||
|
phoneMatch, _ := regexp.MatchString(phoneRegex, value)
|
||||||
|
|
||||||
|
return emailMatch || phoneMatch
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,31 +0,0 @@
|
||||||
package logic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"ark-permission/gen_result/pb/permission"
|
|
||||||
"ark-permission/internal/svc"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CancelTokenByDeviceIDLogic struct {
|
|
||||||
ctx context.Context
|
|
||||||
svcCtx *svc.ServiceContext
|
|
||||||
logx.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCancelTokenByDeviceIDLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CancelTokenByDeviceIDLogic {
|
|
||||||
return &CancelTokenByDeviceIDLogic{
|
|
||||||
ctx: ctx,
|
|
||||||
svcCtx: svcCtx,
|
|
||||||
Logger: logx.WithContext(ctx),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CancelTokenByDeviceID 取消 Token
|
|
||||||
func (l *CancelTokenByDeviceIDLogic) CancelTokenByDeviceID(in *permission.DoTokenByDeviceIDReq) (*permission.OKResp, error) {
|
|
||||||
// todo: add your logic here and delete this line
|
|
||||||
|
|
||||||
return &permission.OKResp{}, nil
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
package logic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"ark-permission/gen_result/pb/permission"
|
|
||||||
"ark-permission/internal/svc"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CancelTokenByUIDLogic struct {
|
|
||||||
ctx context.Context
|
|
||||||
svcCtx *svc.ServiceContext
|
|
||||||
logx.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCancelTokenByUIDLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CancelTokenByUIDLogic {
|
|
||||||
return &CancelTokenByUIDLogic{
|
|
||||||
ctx: ctx,
|
|
||||||
svcCtx: svcCtx,
|
|
||||||
Logger: logx.WithContext(ctx),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CancelTokenByUID 取消 Token (取消這個用戶從不同 Device 登入的所有 Token),也包含他裡面的 One Time Toke
|
|
||||||
func (l *CancelTokenByUIDLogic) CancelTokenByUID(in *permission.DoTokenByUIDReq) (*permission.OKResp, error) {
|
|
||||||
// todo: add your logic here and delete this line
|
|
||||||
|
|
||||||
return &permission.OKResp{}, nil
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
package logic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"ark-permission/gen_result/pb/permission"
|
|
||||||
"ark-permission/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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUserTokensByDeviceIDs 取得目前所對應的 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
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
package logic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"ark-permission/gen_result/pb/permission"
|
|
||||||
"ark-permission/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.DoTokenByUIDReq) (*permission.Tokens, error) {
|
|
||||||
// todo: add your logic here and delete this line
|
|
||||||
|
|
||||||
return &permission.Tokens{}, nil
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
package logic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"ark-permission/gen_result/pb/permission"
|
|
||||||
"ark-permission/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
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
package logic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"ark-permission/gen_result/pb/permission"
|
|
||||||
"ark-permission/internal/svc"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NewTokenLogic struct {
|
|
||||||
ctx context.Context
|
|
||||||
svcCtx *svc.ServiceContext
|
|
||||||
logx.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewNewTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *NewTokenLogic {
|
|
||||||
return &NewTokenLogic{
|
|
||||||
ctx: ctx,
|
|
||||||
svcCtx: svcCtx,
|
|
||||||
Logger: logx.WithContext(ctx),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewToken 建立一個新的 Token,例如:AccessToken
|
|
||||||
func (l *NewTokenLogic) NewToken(in *permission.AuthorizationReq) (*permission.TokenResp, error) {
|
|
||||||
// todo: add your logic here and delete this line
|
|
||||||
|
|
||||||
return &permission.TokenResp{}, nil
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
package logic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"ark-permission/gen_result/pb/permission"
|
|
||||||
"ark-permission/internal/svc"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
|
||||||
)
|
|
||||||
|
|
||||||
type RefreshTokenLogic struct {
|
|
||||||
ctx context.Context
|
|
||||||
svcCtx *svc.ServiceContext
|
|
||||||
logx.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewRefreshTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RefreshTokenLogic {
|
|
||||||
return &RefreshTokenLogic{
|
|
||||||
ctx: ctx,
|
|
||||||
svcCtx: svcCtx,
|
|
||||||
Logger: logx.WithContext(ctx),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RefreshToken 更新目前的token 以及裡面包含的一次性 Token
|
|
||||||
func (l *RefreshTokenLogic) RefreshToken(in *permission.RefreshTokenReq) (*permission.RefreshTokenResp, error) {
|
|
||||||
// todo: add your logic here and delete this line
|
|
||||||
|
|
||||||
return &permission.RefreshTokenResp{}, nil
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package logic
|
package roleservicelogic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -9,22 +9,21 @@ import (
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CancelTokenLogic struct {
|
type PingLogic struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
svcCtx *svc.ServiceContext
|
svcCtx *svc.ServiceContext
|
||||||
logx.Logger
|
logx.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCancelTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CancelTokenLogic {
|
func NewPingLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PingLogic {
|
||||||
return &CancelTokenLogic{
|
return &PingLogic{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
svcCtx: svcCtx,
|
svcCtx: svcCtx,
|
||||||
Logger: logx.WithContext(ctx),
|
Logger: logx.WithContext(ctx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CancelToken 取消 Token,也包含他裡面的 One Time Toke
|
func (l *PingLogic) Ping(in *permission.OKResp) (*permission.OKResp, error) {
|
||||||
func (l *CancelTokenLogic) CancelToken(in *permission.CancelTokenReq) (*permission.OKResp, error) {
|
|
||||||
// todo: add your logic here and delete this line
|
// todo: add your logic here and delete this line
|
||||||
|
|
||||||
return &permission.OKResp{}, nil
|
return &permission.OKResp{}, nil
|
|
@ -1,6 +1,7 @@
|
||||||
package logic
|
package tokenservicelogic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
ers "code.30cm.net/wanderland/library-go/errors"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"ark-permission/gen_result/pb/permission"
|
"ark-permission/gen_result/pb/permission"
|
||||||
|
@ -23,9 +24,23 @@ func NewCancelOneTimeTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CancelOneTimeToken 取消一次性使用
|
type cancelOneTimeTokenReq struct {
|
||||||
func (l *CancelOneTimeTokenLogic) CancelOneTimeToken(in *permission.CreateOneTimeTokenReq) (*permission.CreateOneTimeTokenResp, error) {
|
Token []string `json:"token" validate:"required"`
|
||||||
// todo: add your logic here and delete this line
|
}
|
||||||
|
|
||||||
return &permission.CreateOneTimeTokenResp{}, nil
|
// CancelOneTimeToken 取消一次性使用
|
||||||
|
func (l *CancelOneTimeTokenLogic) CancelOneTimeToken(in *permission.CancelOneTimeTokenReq) (*permission.OKResp, error) {
|
||||||
|
// 驗證所需
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&cancelOneTimeTokenReq{
|
||||||
|
Token: in.GetToken(),
|
||||||
|
}); err != nil {
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err := l.svcCtx.TokenRedisRepo.DeleteOneTimeToken(l.ctx, in.GetToken(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &permission.OKResp{}, nil
|
||||||
}
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package tokenservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
ers "code.30cm.net/wanderland/library-go/errors"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"ark-permission/gen_result/pb/permission"
|
||||||
|
"ark-permission/internal/svc"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CancelTokenByDeviceIdLogic struct {
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
logx.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCancelTokenByDeviceIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CancelTokenByDeviceIdLogic {
|
||||||
|
return &CancelTokenByDeviceIdLogic{
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CancelTokenByDeviceId 取消 Token
|
||||||
|
func (l *CancelTokenByDeviceIdLogic) CancelTokenByDeviceId(in *permission.DoTokenByDeviceIDReq) (*permission.OKResp, error) {
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&getUserTokensByDeviceIdReq{
|
||||||
|
DeviceID: in.GetDeviceId(),
|
||||||
|
}); err != nil {
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err := l.svcCtx.TokenRedisRepo.DeleteAccessTokensByDeviceID(l.ctx, in.GetDeviceId())
|
||||||
|
if err != nil {
|
||||||
|
logx.WithCallerSkip(1).WithFields(
|
||||||
|
logx.Field("func", "TokenRedisRepo.DeleteAccessTokensByDeviceID"),
|
||||||
|
logx.Field("DeviceID", in.GetDeviceId()),
|
||||||
|
).Error(err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &permission.OKResp{}, nil
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package tokenservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ark-permission/gen_result/pb/permission"
|
||||||
|
"ark-permission/internal/svc"
|
||||||
|
ers "code.30cm.net/wanderland/library-go/errors"
|
||||||
|
"context"
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CancelTokenLogic struct {
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
logx.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCancelTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CancelTokenLogic {
|
||||||
|
return &CancelTokenLogic{
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type cancelTokenReq struct {
|
||||||
|
Token string `json:"token" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CancelToken 取消 Token,也包含他裡面的 One Time Toke
|
||||||
|
func (l *CancelTokenLogic) CancelToken(in *permission.CancelTokenReq) (*permission.OKResp, error) {
|
||||||
|
// 驗證所需
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&cancelTokenReq{
|
||||||
|
Token: in.GetToken(),
|
||||||
|
}); err != nil {
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
claims, err := parseClaims(in.GetToken(), l.svcCtx.Config.Token.Secret, false)
|
||||||
|
if err != nil {
|
||||||
|
logx.WithCallerSkip(1).WithFields(
|
||||||
|
logx.Field("func", "parseClaims"),
|
||||||
|
).Error(err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := l.svcCtx.TokenRedisRepo.GetAccessTokenByID(l.ctx, claims.ID())
|
||||||
|
if err != nil {
|
||||||
|
logx.WithCallerSkip(1).WithFields(
|
||||||
|
logx.Field("func", "TokenRedisRepo.GetByAccess"),
|
||||||
|
logx.Field("claims", claims),
|
||||||
|
).Error(err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = l.svcCtx.TokenRedisRepo.Delete(l.ctx, token)
|
||||||
|
if err != nil {
|
||||||
|
logx.WithCallerSkip(1).WithFields(
|
||||||
|
logx.Field("func", "TokenRedisRepo.Delete"),
|
||||||
|
logx.Field("req", token),
|
||||||
|
).Error(err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &permission.OKResp{}, nil
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package tokenservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
ers "code.30cm.net/wanderland/library-go/errors"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"ark-permission/gen_result/pb/permission"
|
||||||
|
"ark-permission/internal/svc"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CancelTokensLogic struct {
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
logx.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCancelTokensLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CancelTokensLogic {
|
||||||
|
return &CancelTokensLogic{
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CancelTokens 取消 Token 從UID 視角,以及 token id 視角出發, UID 登出,底下所有 Device ID 也要登出, Token ID 登出, 所有 UID + Device 都要登出
|
||||||
|
func (l *CancelTokensLogic) CancelTokens(in *permission.DoTokenByUIDReq) (*permission.OKResp, error) {
|
||||||
|
if in.GetUid() != "" {
|
||||||
|
err := l.svcCtx.TokenRedisRepo.DeleteAccessTokensByUID(l.ctx, in.GetUid())
|
||||||
|
if err != nil {
|
||||||
|
logx.WithCallerSkip(1).WithFields(
|
||||||
|
logx.Field("func", "TokenRedisRepo.DeleteAccessTokensByUID"),
|
||||||
|
logx.Field("uid", in.GetUid()),
|
||||||
|
).Error(err.Error())
|
||||||
|
return nil, ers.ResourceInsufficient(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(in.GetIds()) > 0 {
|
||||||
|
err := l.svcCtx.TokenRedisRepo.DeleteAccessTokenByID(l.ctx, in.GetIds())
|
||||||
|
if err != nil {
|
||||||
|
logx.WithCallerSkip(1).WithFields(
|
||||||
|
logx.Field("func", "TokenRedisRepo.DeleteAccessTokenByID"),
|
||||||
|
logx.Field("ids", in.GetIds()),
|
||||||
|
).Error(err.Error())
|
||||||
|
return nil, ers.ResourceInsufficient(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &permission.OKResp{}, nil
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package tokenservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ark-permission/gen_result/pb/permission"
|
||||||
|
"ark-permission/internal/domain"
|
||||||
|
"ark-permission/internal/svc"
|
||||||
|
ers "code.30cm.net/wanderland/library-go/errors"
|
||||||
|
"context"
|
||||||
|
"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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type getUserTokensByDeviceIdReq struct {
|
||||||
|
DeviceID string `json:"device_id" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserTokensByDeviceId 取得目前所對應的 DeviceID 所存在的 Tokens
|
||||||
|
func (l *GetUserTokensByDeviceIdLogic) GetUserTokensByDeviceId(in *permission.DoTokenByDeviceIDReq) (*permission.Tokens, error) {
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&getUserTokensByDeviceIdReq{
|
||||||
|
DeviceID: in.GetDeviceId(),
|
||||||
|
}); err != nil {
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
uidTokens, err := l.svcCtx.TokenRedisRepo.GetAccessTokensByDeviceID(l.ctx, in.GetDeviceId())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens := make([]*permission.TokenResp, 0, len(uidTokens))
|
||||||
|
for _, v := range uidTokens {
|
||||||
|
tokens = append(tokens, &permission.TokenResp{
|
||||||
|
AccessToken: v.AccessToken,
|
||||||
|
TokenType: domain.TokenTypeBearer,
|
||||||
|
ExpiresIn: int32(v.ExpiresIn),
|
||||||
|
RefreshToken: v.RefreshToken,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &permission.Tokens{
|
||||||
|
Token: tokens,
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package tokenservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ark-permission/gen_result/pb/permission"
|
||||||
|
"ark-permission/internal/domain"
|
||||||
|
"ark-permission/internal/svc"
|
||||||
|
ers "code.30cm.net/wanderland/library-go/errors"
|
||||||
|
"context"
|
||||||
|
"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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type getUserTokensByUidReq struct {
|
||||||
|
UID string `json:"uid" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserTokensByUid 取得目前所對應的 UID 所存在的 Tokens
|
||||||
|
func (l *GetUserTokensByUidLogic) GetUserTokensByUid(in *permission.QueryTokenByUIDReq) (*permission.Tokens, error) {
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&getUserTokensByUidReq{
|
||||||
|
UID: in.GetUid(),
|
||||||
|
}); err != nil {
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
uidTokens, err := l.svcCtx.TokenRedisRepo.GetAccessTokensByUID(l.ctx, in.GetUid())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens := make([]*permission.TokenResp, 0, len(uidTokens))
|
||||||
|
for _, v := range uidTokens {
|
||||||
|
tokens = append(tokens, &permission.TokenResp{
|
||||||
|
AccessToken: v.AccessToken,
|
||||||
|
TokenType: domain.TokenTypeBearer,
|
||||||
|
ExpiresIn: int32(v.ExpiresIn),
|
||||||
|
RefreshToken: v.RefreshToken,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &permission.Tokens{
|
||||||
|
Token: tokens,
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package tokenservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ark-permission/internal/domain"
|
||||||
|
"ark-permission/internal/entity"
|
||||||
|
ers "code.30cm.net/wanderland/library-go/errors"
|
||||||
|
"context"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ark-permission/gen_result/pb/permission"
|
||||||
|
"ark-permission/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 TODO 目前並無後續操作
|
||||||
|
func (l *NewOneTimeTokenLogic) NewOneTimeToken(in *permission.CreateOneTimeTokenReq) (*permission.CreateOneTimeTokenResp, error) {
|
||||||
|
// 驗證所需
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&refreshTokenReq{
|
||||||
|
Token: in.GetToken(),
|
||||||
|
}); err != nil {
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 驗證Token
|
||||||
|
claims, err := parseClaims(in.GetToken(), l.svcCtx.Config.Token.Secret, false)
|
||||||
|
if err != nil {
|
||||||
|
logx.WithCallerSkip(1).WithFields(
|
||||||
|
logx.Field("func", "parseClaims"),
|
||||||
|
).Error(err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := l.svcCtx.TokenRedisRepo.GetAccessTokenByID(l.ctx, claims.ID())
|
||||||
|
if err != nil {
|
||||||
|
logx.WithCallerSkip(1).WithFields(
|
||||||
|
logx.Field("func", "TokenRedisRepo.GetByAccess"),
|
||||||
|
logx.Field("claims", claims),
|
||||||
|
).Error(err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
oneTimeToken := generateRefreshToken(uuid.Must(uuid.NewRandom()).String())
|
||||||
|
key := domain.TicketKeyPrefix + oneTimeToken
|
||||||
|
if err = l.svcCtx.TokenRedisRepo.CreateOneTimeToken(l.ctx, key, entity.Ticket{
|
||||||
|
Data: claims,
|
||||||
|
Token: token,
|
||||||
|
}, time.Minute); err != nil {
|
||||||
|
return &permission.CreateOneTimeTokenResp{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &permission.CreateOneTimeTokenResp{
|
||||||
|
OneTimeToken: oneTimeToken,
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -0,0 +1,138 @@
|
||||||
|
package tokenservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ark-permission/internal/config"
|
||||||
|
"ark-permission/internal/domain"
|
||||||
|
"ark-permission/internal/entity"
|
||||||
|
ers "code.30cm.net/wanderland/library-go/errors"
|
||||||
|
"context"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ark-permission/gen_result/pb/permission"
|
||||||
|
"ark-permission/internal/svc"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NewTokenLogic struct {
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
logx.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNewTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *NewTokenLogic {
|
||||||
|
return &NewTokenLogic{
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://datatracker.ietf.org/doc/html/rfc6749#section-3.3
|
||||||
|
type authorizationReq struct {
|
||||||
|
GrantType domain.GrantType `json:"grant_type" validate:"required,oneof=password client_credentials refresh_token"`
|
||||||
|
DeviceID string `json:"device_id"`
|
||||||
|
Scope string `json:"scope" validate:"required"`
|
||||||
|
Data map[string]string `json:"data"`
|
||||||
|
Expires int `json:"expires"`
|
||||||
|
IsRefreshToken bool `json:"is_refresh_token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewToken 建立一個新的 Token,例如:AccessToken
|
||||||
|
func (l *NewTokenLogic) NewToken(in *permission.AuthorizationReq) (*permission.TokenResp, error) {
|
||||||
|
data := authorizationReq{
|
||||||
|
GrantType: domain.GrantType(in.GetGrantType()),
|
||||||
|
Scope: in.GetScope(),
|
||||||
|
DeviceID: in.GetDeviceId(),
|
||||||
|
Data: in.GetData(),
|
||||||
|
Expires: int(in.GetExpires()),
|
||||||
|
IsRefreshToken: in.GetIsRefreshToken(),
|
||||||
|
}
|
||||||
|
// 驗證所需
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&data); err != nil {
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
token, err := newToken(data, l.svcCtx.Config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = l.svcCtx.TokenRedisRepo.Create(l.ctx, *token)
|
||||||
|
if err != nil {
|
||||||
|
logx.WithCallerSkip(1).WithFields(
|
||||||
|
logx.Field("func", "TokenRedisRepo.Create"),
|
||||||
|
logx.Field("token", token),
|
||||||
|
).Error(err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &permission.TokenResp{
|
||||||
|
AccessToken: token.AccessToken,
|
||||||
|
TokenType: domain.TokenTypeBearer,
|
||||||
|
ExpiresIn: int32(token.ExpiresIn),
|
||||||
|
RefreshToken: token.RefreshToken,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newToken(authReq authorizationReq, cfg config.Config) (*entity.Token, error) {
|
||||||
|
// 準備建立 Token 所需
|
||||||
|
now := time.Now().UTC()
|
||||||
|
expires := authReq.Expires
|
||||||
|
refreshExpires := authReq.Expires
|
||||||
|
if expires <= 0 {
|
||||||
|
// 將時間加上 300 秒
|
||||||
|
sec := time.Duration(cfg.Token.Expired.Seconds()) * time.Second
|
||||||
|
newTime := now.Add(sec)
|
||||||
|
// 獲取 Unix 時間戳
|
||||||
|
timestamp := newTime.Unix()
|
||||||
|
expires = int(timestamp)
|
||||||
|
refreshExpires = expires
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果這是一個 Refresh Token 過期時間要比普通的Token 長
|
||||||
|
if authReq.IsRefreshToken {
|
||||||
|
// 將時間加上 300 秒
|
||||||
|
sec := time.Duration(cfg.Token.RefreshExpires.Seconds()) * time.Second
|
||||||
|
newTime := now.Add(sec)
|
||||||
|
// 獲取 Unix 時間戳
|
||||||
|
timestamp := newTime.Unix()
|
||||||
|
refreshExpires = int(timestamp)
|
||||||
|
}
|
||||||
|
|
||||||
|
token := entity.Token{
|
||||||
|
ID: uuid.Must(uuid.NewRandom()).String(),
|
||||||
|
DeviceID: authReq.DeviceID,
|
||||||
|
ExpiresIn: expires,
|
||||||
|
RefreshExpiresIn: refreshExpires,
|
||||||
|
AccessCreateAt: now,
|
||||||
|
RefreshCreateAt: now,
|
||||||
|
}
|
||||||
|
|
||||||
|
claims := claims(authReq.Data)
|
||||||
|
claims.SetRole(domain.DefaultRole)
|
||||||
|
claims.SetID(token.ID)
|
||||||
|
claims.SetScope(authReq.Scope)
|
||||||
|
|
||||||
|
token.UID = claims.UID()
|
||||||
|
|
||||||
|
if authReq.DeviceID != "" {
|
||||||
|
claims.SetDeviceID(authReq.DeviceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
token.AccessToken, err = generateAccessTokenFunc(token, claims, cfg.Token.Secret)
|
||||||
|
if err != nil {
|
||||||
|
logx.WithCallerSkip(1).WithFields(
|
||||||
|
logx.Field("func", "generateAccessTokenFunc"),
|
||||||
|
logx.Field("claims", claims),
|
||||||
|
).Error(err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if authReq.IsRefreshToken {
|
||||||
|
token.RefreshToken = generateRefreshTokenFunc(token.AccessToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &token, nil
|
||||||
|
}
|
|
@ -0,0 +1,199 @@
|
||||||
|
package tokenservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ark-permission/internal/entity"
|
||||||
|
"github.com/golang-jwt/jwt/v4"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// func TestNewTokenLogic_NewToken(t *testing.T) {
|
||||||
|
// // mock
|
||||||
|
// ctrl := gomock.NewController(t)
|
||||||
|
// defer ctrl.Finish()
|
||||||
|
//
|
||||||
|
// tokenMockRepo := repoMock.NewMockTokenRepository(ctrl)
|
||||||
|
// mockValidate := libMock.NewMockValidate(ctrl)
|
||||||
|
//
|
||||||
|
// sc := svc.ServiceContext{
|
||||||
|
// TokenRedisRepo: tokenMockRepo,
|
||||||
|
// Validate: mockValidate,
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// l := NewNewTokenLogic(context.Background(), &sc)
|
||||||
|
//
|
||||||
|
// tests := []struct {
|
||||||
|
// name string
|
||||||
|
// input *permission.AuthorizationReq
|
||||||
|
// setupMocks func()
|
||||||
|
// expectError bool
|
||||||
|
// expected *permission.TokenResp
|
||||||
|
// }{
|
||||||
|
// {
|
||||||
|
// name: "Valid token request",
|
||||||
|
// input: &permission.AuthorizationReq{
|
||||||
|
// GrantType: "authorization_code",
|
||||||
|
// DeviceId: "device123",
|
||||||
|
// Scope: "read",
|
||||||
|
// Expires: 3600,
|
||||||
|
// IsRefreshToken: false,
|
||||||
|
// Data: map[string]string{
|
||||||
|
// "uid": "user123",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// setupMocks: func() {
|
||||||
|
// mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil)
|
||||||
|
// tokenMockRepo.EXPECT().Create(gomock.Any(), gomock.Any()).Return(nil).Do(func(ctx context.Context, token entity.Token) {
|
||||||
|
// token.AccessToken = "access_token"
|
||||||
|
// })
|
||||||
|
// generateAccessTokenFunc = func(token entity.Token, data any, sign string) (string, error) {
|
||||||
|
// return "access_token", nil
|
||||||
|
// }
|
||||||
|
// generateRefreshTokenFunc = func(accessToken string) string {
|
||||||
|
// return "refresh_token"
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// expectError: false,
|
||||||
|
// expected: &permission.TokenResp{
|
||||||
|
// AccessToken: "access_token",
|
||||||
|
// TokenType: domain.TokenTypeBearer,
|
||||||
|
// ExpiresIn: 3600,
|
||||||
|
// RefreshToken: "",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: "Validation error",
|
||||||
|
// input: &permission.AuthorizationReq{
|
||||||
|
// GrantType: "invalid_grant",
|
||||||
|
// DeviceId: "device123",
|
||||||
|
// Scope: "read",
|
||||||
|
// Expires: 3600,
|
||||||
|
// IsRefreshToken: false,
|
||||||
|
// Data: map[string]string{
|
||||||
|
// "uid": "user123",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// setupMocks: func() {
|
||||||
|
// mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(errors.New("invalid grant type"))
|
||||||
|
// },
|
||||||
|
// expectError: true,
|
||||||
|
// expected: nil,
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
// for _, tt := range tests {
|
||||||
|
// t.Run(tt.name, func(t *testing.T) {
|
||||||
|
// tt.setupMocks()
|
||||||
|
//
|
||||||
|
// resp, err := l.NewToken(tt.input)
|
||||||
|
// if tt.expectError {
|
||||||
|
// assert.Error(t, err)
|
||||||
|
// } else {
|
||||||
|
// assert.NoError(t, err)
|
||||||
|
// assert.Equal(t, tt.expected, resp)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 測試 generateAccessToken 函數
|
||||||
|
func TestGenerateAccessToken(t *testing.T) {
|
||||||
|
// 定義測試用例
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
token entity.Token
|
||||||
|
data any
|
||||||
|
sign string
|
||||||
|
shouldFail bool
|
||||||
|
shouldVerify bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Valid token with admin role",
|
||||||
|
token: entity.Token{
|
||||||
|
ID: "123",
|
||||||
|
ExpiresIn: int(time.Now().Add(time.Hour * 24).Unix()),
|
||||||
|
},
|
||||||
|
data: map[string]string{"role": "admin"},
|
||||||
|
sign: "secret",
|
||||||
|
shouldFail: false,
|
||||||
|
shouldVerify: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Expired token",
|
||||||
|
token: entity.Token{
|
||||||
|
ID: "456",
|
||||||
|
ExpiresIn: int(time.Now().Add(-time.Hour * 24).Unix()), // 過期時間
|
||||||
|
},
|
||||||
|
data: map[string]string{"role": "user"},
|
||||||
|
sign: "secret",
|
||||||
|
shouldFail: false, // 這個測試不會失敗,因為過期檢查通常在驗證時進行
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
tokenString, err := generateAccessToken(tt.token, tt.data, tt.sign)
|
||||||
|
if (err != nil) != tt.shouldFail {
|
||||||
|
t.Errorf("generateAccessToken() error = %v, shouldFail %v", err, tt.shouldFail)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.shouldVerify {
|
||||||
|
// 驗證生成的 token
|
||||||
|
parsedToken, err := jwt.ParseWithClaims(tokenString, &entity.Claims{}, func(token *jwt.Token) (interface{}, error) {
|
||||||
|
return []byte(tt.sign), nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error parsing token: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if claims, ok := parsedToken.Claims.(*entity.Claims); ok && parsedToken.Valid {
|
||||||
|
if claims.ID != tt.token.ID {
|
||||||
|
t.Errorf("Expected ID %v, got %v", tt.token.ID, claims.ID)
|
||||||
|
}
|
||||||
|
if claims.Issuer != "permission" {
|
||||||
|
t.Errorf("Expected Issuer 'permission', got %v", claims.Issuer)
|
||||||
|
}
|
||||||
|
for k, v := range tt.data.(map[string]string) {
|
||||||
|
if claims.Data.(map[string]any)[k] != v {
|
||||||
|
t.Errorf("Expected data %v, got %v", v, claims.Data.(map[string]string)[k])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Errorf("Invalid token claims")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 測試 generateRefreshToken 函數
|
||||||
|
func TestGenerateRefreshToken(t *testing.T) {
|
||||||
|
// 定義測試用例
|
||||||
|
tests := []struct {
|
||||||
|
accessToken string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
accessToken: "test_access_token",
|
||||||
|
expected: "4993552f2cc6c4e57fa5738f9b161a1a4051c8370cddb32514c8f6f4c797801f",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessToken: "another_test_access_token",
|
||||||
|
expected: "8361833e9a11f829f2be9a00f1939b5a72408ff829451169f3b223c41768cfa2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessToken: "",
|
||||||
|
expected: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.accessToken, func(t *testing.T) {
|
||||||
|
got := generateRefreshToken(tt.accessToken)
|
||||||
|
if got != tt.expected {
|
||||||
|
t.Errorf("generateRefreshToken(%s) = %s; want %s", tt.accessToken, got, tt.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
package tokenservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ark-permission/gen_result/pb/permission"
|
||||||
|
"ark-permission/internal/domain"
|
||||||
|
"ark-permission/internal/svc"
|
||||||
|
ers "code.30cm.net/wanderland/library-go/errors"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RefreshTokenLogic struct {
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
logx.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRefreshTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RefreshTokenLogic {
|
||||||
|
return &RefreshTokenLogic{
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type refreshReq struct {
|
||||||
|
RefreshToken string `json:"grant_type" validate:"required"`
|
||||||
|
DeviceID string `json:"device_id" validate:"required"`
|
||||||
|
Scope string `json:"scope" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RefreshToken 更新目前的token 以及裡面包含的一次性 Token
|
||||||
|
func (l *RefreshTokenLogic) RefreshToken(in *permission.RefreshTokenReq) (*permission.RefreshTokenResp, error) {
|
||||||
|
// 驗證所需
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&refreshReq{
|
||||||
|
RefreshToken: in.GetToken(),
|
||||||
|
Scope: in.GetScope(),
|
||||||
|
DeviceID: in.GetDeviceId(),
|
||||||
|
}); err != nil {
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// step 1 拿看看有沒有這個 refresh token
|
||||||
|
token, err := l.svcCtx.TokenRedisRepo.GetAccessTokenByByOneTimeToken(l.ctx, in.Token)
|
||||||
|
if err != nil {
|
||||||
|
logx.WithCallerSkip(1).WithFields(
|
||||||
|
logx.Field("func", "TokenRedisRepo.GetByRefresh"),
|
||||||
|
logx.Field("req", in),
|
||||||
|
).Error(err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取得 Data
|
||||||
|
c, err := parseClaims(token.AccessToken, l.svcCtx.Config.Token.Secret, false)
|
||||||
|
if err != nil {
|
||||||
|
logx.WithCallerSkip(1).WithFields(
|
||||||
|
logx.Field("func", "parseClaims"),
|
||||||
|
logx.Field("token", token),
|
||||||
|
).Error(err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// step 2 建立新 token
|
||||||
|
nt, err := newToken(authorizationReq{
|
||||||
|
GrantType: domain.ClientCredentials,
|
||||||
|
Scope: in.GetScope(),
|
||||||
|
DeviceID: in.GetDeviceId(),
|
||||||
|
Data: c,
|
||||||
|
Expires: int(in.GetExpires()),
|
||||||
|
IsRefreshToken: true,
|
||||||
|
}, l.svcCtx.Config)
|
||||||
|
if err != nil {
|
||||||
|
logx.WithCallerSkip(1).WithFields(
|
||||||
|
logx.Field("func", "newToken"),
|
||||||
|
logx.Field("req", in),
|
||||||
|
).Error(err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 刪除掉舊的 token
|
||||||
|
err = l.svcCtx.TokenRedisRepo.Delete(l.ctx, token)
|
||||||
|
if err != nil {
|
||||||
|
logx.WithCallerSkip(1).WithFields(
|
||||||
|
logx.Field("func", "TokenRedisRepo.Delete"),
|
||||||
|
logx.Field("req", token),
|
||||||
|
).Error(err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = l.svcCtx.TokenRedisRepo.Create(l.ctx, *nt)
|
||||||
|
if err != nil {
|
||||||
|
logx.WithCallerSkip(1).WithFields(
|
||||||
|
logx.Field("func", "TokenRedisRepo.Create"),
|
||||||
|
logx.Field("token", token),
|
||||||
|
).Error(err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &permission.RefreshTokenResp{
|
||||||
|
Token: nt.AccessToken,
|
||||||
|
OneTimeToken: nt.RefreshToken,
|
||||||
|
ExpiresIn: int64(nt.ExpiresIn),
|
||||||
|
TokenType: domain.TokenTypeBearer,
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package tokenservicelogic
|
||||||
|
|
||||||
|
type claims map[string]string
|
||||||
|
|
||||||
|
func (c claims) SetID(id string) {
|
||||||
|
c["id"] = id
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c claims) SetRole(role string) {
|
||||||
|
c["role"] = role
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c claims) SetDeviceID(deviceID string) {
|
||||||
|
c["device_id"] = deviceID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c claims) SetScope(scope string) {
|
||||||
|
c["scope"] = scope
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c claims) Role() string {
|
||||||
|
role, ok := c["role"]
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return role
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c claims) ID() string {
|
||||||
|
id, ok := c["id"]
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c claims) DeviceID() string {
|
||||||
|
deviceID, ok := c["device_id"]
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return deviceID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c claims) UID() string {
|
||||||
|
uid, ok := c["uid"]
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return uid
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
package tokenservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ark-permission/internal/domain"
|
||||||
|
"ark-permission/internal/entity"
|
||||||
|
"bytes"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"github.com/golang-jwt/jwt/v4"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var generateAccessTokenFunc = generateAccessToken
|
||||||
|
var generateRefreshTokenFunc = generateRefreshToken
|
||||||
|
|
||||||
|
func generateAccessToken(token entity.Token, data any, sign string) (string, error) {
|
||||||
|
claim := entity.Claims{
|
||||||
|
Data: data,
|
||||||
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
|
ID: token.ID,
|
||||||
|
ExpiresAt: jwt.NewNumericDate(time.Unix(int64(token.ExpiresIn), 0)),
|
||||||
|
Issuer: "permission",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
accessToken, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claim).
|
||||||
|
SignedString([]byte(sign))
|
||||||
|
if err != nil {
|
||||||
|
return "", domain.TokenClaimError(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return accessToken, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateRefreshToken(accessToken string) string {
|
||||||
|
buf := bytes.NewBufferString(accessToken)
|
||||||
|
h := sha256.New()
|
||||||
|
_, _ = h.Write(buf.Bytes())
|
||||||
|
|
||||||
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseToken(accessToken string, secret string, validate bool) (jwt.MapClaims, error) {
|
||||||
|
// 跳過驗證的解析
|
||||||
|
var token *jwt.Token
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if validate {
|
||||||
|
token, err = jwt.Parse(accessToken, func(token *jwt.Token) (interface{}, error) {
|
||||||
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||||
|
return nil, domain.TokenUnexpectedSigningErr(fmt.Sprintf("token unexpected signing method: %v", token.Header["alg"]))
|
||||||
|
}
|
||||||
|
return []byte(secret), nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return jwt.MapClaims{}, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parser := jwt.NewParser(jwt.WithoutClaimsValidation())
|
||||||
|
token, err = parser.Parse(accessToken, func(token *jwt.Token) (interface{}, error) {
|
||||||
|
return []byte(secret), nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return jwt.MapClaims{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
claims, ok := token.Claims.(jwt.MapClaims)
|
||||||
|
if !ok && token.Valid {
|
||||||
|
return jwt.MapClaims{}, domain.TokenTokenValidateErr("token valid error")
|
||||||
|
}
|
||||||
|
|
||||||
|
return claims, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseClaims(accessToken string, secret string, validate bool) (claims, error) {
|
||||||
|
claimMap, err := parseToken(accessToken, secret, validate)
|
||||||
|
if err != nil {
|
||||||
|
return claims{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
claimsData, ok := claimMap["data"].(map[string]any)
|
||||||
|
if ok {
|
||||||
|
return convertMap(claimsData), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return claims{}, domain.TokenClaimError("get data from claim map error")
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertMap(input map[string]interface{}) map[string]string {
|
||||||
|
output := make(map[string]string)
|
||||||
|
for key, value := range input {
|
||||||
|
switch v := value.(type) {
|
||||||
|
case string:
|
||||||
|
output[key] = v
|
||||||
|
case fmt.Stringer:
|
||||||
|
output[key] = v.String()
|
||||||
|
default:
|
||||||
|
output[key] = fmt.Sprintf("%v", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
package tokenservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ark-permission/gen_result/pb/permission"
|
||||||
|
"ark-permission/internal/svc"
|
||||||
|
ers "code.30cm.net/wanderland/library-go/errors"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ValidationTokenLogic struct {
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
logx.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewValidationTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ValidationTokenLogic {
|
||||||
|
return &ValidationTokenLogic{
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type refreshTokenReq struct {
|
||||||
|
Token string `json:"token" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidationToken 驗證這個 Token 有沒有效
|
||||||
|
func (l *ValidationTokenLogic) ValidationToken(in *permission.ValidationTokenReq) (*permission.ValidationTokenResp, error) {
|
||||||
|
// 驗證所需
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&refreshTokenReq{
|
||||||
|
Token: in.GetToken(),
|
||||||
|
}); err != nil {
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
claims, err := parseClaims(in.GetToken(), l.svcCtx.Config.Token.Secret, true)
|
||||||
|
if err != nil {
|
||||||
|
logx.WithCallerSkip(1).WithFields(
|
||||||
|
logx.Field("func", "parseClaims"),
|
||||||
|
).Info(err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
token, err := l.svcCtx.TokenRedisRepo.GetAccessTokenByID(l.ctx, claims.ID())
|
||||||
|
if err != nil {
|
||||||
|
logx.WithCallerSkip(1).WithFields(
|
||||||
|
logx.Field("func", "TokenRedisRepo.GetByAccess"),
|
||||||
|
logx.Field("claims", claims),
|
||||||
|
).Error(err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &permission.ValidationTokenResp{
|
||||||
|
Token: &permission.Token{
|
||||||
|
Id: token.ID,
|
||||||
|
Uid: token.UID,
|
||||||
|
DeviceId: token.DeviceID,
|
||||||
|
AccessCreateAt: token.AccessCreateAt.Unix(),
|
||||||
|
AccessToken: token.AccessToken,
|
||||||
|
ExpiresIn: int32(token.ExpiresIn),
|
||||||
|
RefreshToken: token.RefreshToken,
|
||||||
|
RefreshExpiresIn: int32(token.RefreshExpiresIn),
|
||||||
|
RefreshCreateAt: token.RefreshCreateAt.Unix(),
|
||||||
|
},
|
||||||
|
Data: claims,
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -1,31 +0,0 @@
|
||||||
package logic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"ark-permission/gen_result/pb/permission"
|
|
||||||
"ark-permission/internal/svc"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ValidationTokenLogic struct {
|
|
||||||
ctx context.Context
|
|
||||||
svcCtx *svc.ServiceContext
|
|
||||||
logx.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewValidationTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ValidationTokenLogic {
|
|
||||||
return &ValidationTokenLogic{
|
|
||||||
ctx: ctx,
|
|
||||||
svcCtx: svcCtx,
|
|
||||||
Logger: logx.WithContext(ctx),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidationToken 驗證這個 Token 有沒有效
|
|
||||||
func (l *ValidationTokenLogic) ValidationToken(in *permission.ValidationTokenReq) (*permission.ValidationTokenResp, error) {
|
|
||||||
// todo: add your logic here and delete this line
|
|
||||||
|
|
||||||
return &permission.ValidationTokenResp{}, nil
|
|
||||||
}
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
// Code generated by MockGen. DO NOT EDIT.
|
||||||
|
// Source: ./validate.go
|
||||||
|
//
|
||||||
|
// Generated by this command:
|
||||||
|
//
|
||||||
|
// mockgen -source=./validate.go -destination=../../mock/lib/validate.go -package=lib
|
||||||
|
//
|
||||||
|
|
||||||
|
// Package lib is a generated GoMock package.
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
required "ark-permission/internal/lib/required"
|
||||||
|
reflect "reflect"
|
||||||
|
|
||||||
|
gomock "go.uber.org/mock/gomock"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockValidate is a mock of Validate interface.
|
||||||
|
type MockValidate struct {
|
||||||
|
ctrl *gomock.Controller
|
||||||
|
recorder *MockValidateMockRecorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockValidateMockRecorder is the mock recorder for MockValidate.
|
||||||
|
type MockValidateMockRecorder struct {
|
||||||
|
mock *MockValidate
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMockValidate creates a new mock instance.
|
||||||
|
func NewMockValidate(ctrl *gomock.Controller) *MockValidate {
|
||||||
|
mock := &MockValidate{ctrl: ctrl}
|
||||||
|
mock.recorder = &MockValidateMockRecorder{mock}
|
||||||
|
return mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||||
|
func (m *MockValidate) EXPECT() *MockValidateMockRecorder {
|
||||||
|
return m.recorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindToValidator mocks base method.
|
||||||
|
func (m *MockValidate) BindToValidator(opts ...required.Option) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
varargs := []any{}
|
||||||
|
for _, a := range opts {
|
||||||
|
varargs = append(varargs, a)
|
||||||
|
}
|
||||||
|
ret := m.ctrl.Call(m, "BindToValidator", varargs...)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindToValidator indicates an expected call of BindToValidator.
|
||||||
|
func (mr *MockValidateMockRecorder) BindToValidator(opts ...any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BindToValidator", reflect.TypeOf((*MockValidate)(nil).BindToValidator), opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateAll mocks base method.
|
||||||
|
func (m *MockValidate) ValidateAll(obj any) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "ValidateAll", obj)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateAll indicates an expected call of ValidateAll.
|
||||||
|
func (mr *MockValidateMockRecorder) ValidateAll(obj any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateAll", reflect.TypeOf((*MockValidate)(nil).ValidateAll), obj)
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
// Code generated by MockGen. DO NOT EDIT.
|
||||||
|
// Source: ./token.go
|
||||||
|
//
|
||||||
|
// Generated by this command:
|
||||||
|
//
|
||||||
|
// mockgen -source=./token.go -destination=../../mock/repository/token.go -package=repository
|
||||||
|
//
|
||||||
|
|
||||||
|
// Package repository is a generated GoMock package.
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
entity "ark-permission/internal/entity"
|
||||||
|
context "context"
|
||||||
|
reflect "reflect"
|
||||||
|
|
||||||
|
gomock "go.uber.org/mock/gomock"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockTokenRepository is a mock of TokenRepository interface.
|
||||||
|
type MockTokenRepository struct {
|
||||||
|
ctrl *gomock.Controller
|
||||||
|
recorder *MockTokenRepositoryMockRecorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockTokenRepositoryMockRecorder is the mock recorder for MockTokenRepository.
|
||||||
|
type MockTokenRepositoryMockRecorder struct {
|
||||||
|
mock *MockTokenRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMockTokenRepository creates a new mock instance.
|
||||||
|
func NewMockTokenRepository(ctrl *gomock.Controller) *MockTokenRepository {
|
||||||
|
mock := &MockTokenRepository{ctrl: ctrl}
|
||||||
|
mock.recorder = &MockTokenRepositoryMockRecorder{mock}
|
||||||
|
return mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||||
|
func (m *MockTokenRepository) EXPECT() *MockTokenRepositoryMockRecorder {
|
||||||
|
return m.recorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create mocks base method.
|
||||||
|
func (m *MockTokenRepository) Create(ctx context.Context, token entity.Token) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "Create", ctx, token)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create indicates an expected call of Create.
|
||||||
|
func (mr *MockTokenRepositoryMockRecorder) Create(ctx, token any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockTokenRepository)(nil).Create), ctx, token)
|
||||||
|
}
|
|
@ -0,0 +1,301 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ark-permission/internal/domain"
|
||||||
|
"ark-permission/internal/domain/repository"
|
||||||
|
"ark-permission/internal/entity"
|
||||||
|
ers "code.30cm.net/wanderland/library-go/errors"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/stores/redis"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TokenRepositoryParam struct {
|
||||||
|
Store *redis.Redis `name:"redis"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type tokenRepository struct {
|
||||||
|
store *redis.Redis
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTokenRepository(param TokenRepositoryParam) repository.TokenRepository {
|
||||||
|
return &tokenRepository{
|
||||||
|
store: param.Store,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) Create(ctx context.Context, token entity.Token) error {
|
||||||
|
body, err := json.Marshal(token)
|
||||||
|
if err != nil {
|
||||||
|
return ers.ArkInternal("json.Marshal token error", err.Error())
|
||||||
|
}
|
||||||
|
if err := t.store.Pipelined(func(tx redis.Pipeliner) error {
|
||||||
|
refreshTTL := time.Duration(token.RedisRefreshExpiredSec()) * time.Second
|
||||||
|
|
||||||
|
if err := t.setToken(ctx, tx, token, body, refreshTTL); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := t.setRefreshToken(ctx, tx, token, refreshTTL); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return t.setRelation(ctx, tx, token.UID, token.DeviceID, token.ID, refreshTTL)
|
||||||
|
}); err != nil {
|
||||||
|
return domain.RedisPipLineError(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) Delete(ctx context.Context, token entity.Token) error {
|
||||||
|
keys := []string{
|
||||||
|
domain.GetAccessTokenRedisKey(token.ID),
|
||||||
|
domain.RefreshTokenRedisKey.With(token.RefreshToken).ToString(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := t.deleteKeys(ctx, keys...); err != nil {
|
||||||
|
return domain.RedisPipLineError(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _ = t.store.Srem(domain.DeviceTokenRedisKey.With(token.DeviceID).ToString(), token.ID)
|
||||||
|
_, _ = t.store.Srem(domain.UIDTokenRedisKey.With(token.UID).ToString(), token.ID)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) GetAccessTokenByID(ctx context.Context, id string) (entity.Token, error) {
|
||||||
|
token, err := t.get(ctx, domain.GetAccessTokenRedisKey(id))
|
||||||
|
if err != nil {
|
||||||
|
return entity.Token{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) DeleteAccessTokensByUID(ctx context.Context, uid string) error {
|
||||||
|
tokens, err := t.GetAccessTokensByUID(ctx, uid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, token := range tokens {
|
||||||
|
if err := t.Delete(ctx, token); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) DeleteAccessTokenByID(ctx context.Context, ids []string) error {
|
||||||
|
for _, tokenID := range ids {
|
||||||
|
token, err := t.GetAccessTokenByID(ctx, tokenID)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
keys := []string{
|
||||||
|
domain.GetAccessTokenRedisKey(token.ID),
|
||||||
|
domain.RefreshTokenRedisKey.With(token.RefreshToken).ToString(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := t.deleteKeys(ctx, keys...); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _ = t.store.Srem(domain.DeviceTokenRedisKey.With(token.DeviceID).ToString(), token.ID)
|
||||||
|
_, _ = t.store.Srem(domain.UIDTokenRedisKey.With(token.UID).ToString(), token.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) GetAccessTokensByUID(ctx context.Context, uid string) ([]entity.Token, error) {
|
||||||
|
return t.getTokensBySet(ctx, domain.GetUIDTokenRedisKey(uid))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) GetAccessTokensByDeviceID(ctx context.Context, deviceID string) ([]entity.Token, error) {
|
||||||
|
return t.getTokensBySet(ctx, domain.DeviceTokenRedisKey.With(deviceID).ToString())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) DeleteAccessTokensByDeviceID(ctx context.Context, deviceID string) error {
|
||||||
|
|
||||||
|
tokens, err := t.GetAccessTokensByDeviceID(ctx, deviceID)
|
||||||
|
if err != nil {
|
||||||
|
return domain.RedisDelError(fmt.Sprintf("GetAccessTokensByDeviceID error: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
var keys []string
|
||||||
|
for _, token := range tokens {
|
||||||
|
keys = append(keys, domain.GetAccessTokenRedisKey(token.ID))
|
||||||
|
keys = append(keys, domain.RefreshTokenRedisKey.With(token.RefreshToken).ToString())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
err = t.store.Pipelined(func(tx redis.Pipeliner) error {
|
||||||
|
for _, token := range tokens {
|
||||||
|
_, _ = t.store.Srem(domain.UIDTokenRedisKey.With(token.UID).ToString(), token.ID)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := t.deleteKeys(ctx, keys...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = t.store.Del(domain.DeviceTokenRedisKey.With(deviceID).ToString())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) GetAccessTokenCountByDeviceID(deviceID string) (int, error) {
|
||||||
|
return t.getCountBySet(domain.DeviceTokenRedisKey.With(deviceID).ToString())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) GetAccessTokenCountByUID(uid string) (int, error) {
|
||||||
|
return t.getCountBySet(domain.UIDTokenRedisKey.With(uid).ToString())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) GetAccessTokenByByOneTimeToken(ctx context.Context, oneTimeToken string) (entity.Token, error) {
|
||||||
|
id, err := t.store.Get(domain.RefreshTokenRedisKey.With(oneTimeToken).ToString())
|
||||||
|
if err != nil {
|
||||||
|
return entity.Token{}, domain.RedisError(fmt.Sprintf("GetAccessTokenByByOneTimeToken store.Get error: %s", err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
|
if id == "" {
|
||||||
|
return entity.Token{}, ers.ResourceNotFound("token key not found in redis", domain.RefreshTokenRedisKey.With(oneTimeToken).ToString())
|
||||||
|
}
|
||||||
|
|
||||||
|
return t.GetAccessTokenByID(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) DeleteOneTimeToken(ctx context.Context, ids []string, tokens []entity.Token) error {
|
||||||
|
var keys []string
|
||||||
|
|
||||||
|
for _, id := range ids {
|
||||||
|
keys = append(keys, domain.RefreshTokenRedisKey.With(id).ToString())
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, token := range tokens {
|
||||||
|
keys = append(keys, domain.RefreshTokenRedisKey.With(token.RefreshToken).ToString())
|
||||||
|
}
|
||||||
|
|
||||||
|
return t.deleteKeys(ctx, keys...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) CreateOneTimeToken(ctx context.Context, key string, ticket entity.Ticket, expires time.Duration) error {
|
||||||
|
body, err := json.Marshal(ticket)
|
||||||
|
if err != nil {
|
||||||
|
return ers.InvalidFormat("CreateOneTimeToken json.Marshal error", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = t.store.SetnxEx(domain.RefreshTokenRedisKey.With(key).ToString(), string(body), int(expires.Seconds()))
|
||||||
|
if err != nil {
|
||||||
|
return domain.RedisError(fmt.Sprintf("CreateOneTimeToken store.SetnxEx error: %s", err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------- Private area --------------------
|
||||||
|
|
||||||
|
func (t *tokenRepository) get(ctx context.Context, key string) (entity.Token, error) {
|
||||||
|
body, err := t.store.GetCtx(ctx, key)
|
||||||
|
if err != nil {
|
||||||
|
return entity.Token{}, domain.RedisError(fmt.Sprintf("token %s not found in redis: %s", key, err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
|
if body == "" {
|
||||||
|
return entity.Token{}, ers.ResourceNotFound("this token not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
var token entity.Token
|
||||||
|
if err := json.Unmarshal([]byte(body), &token); err != nil {
|
||||||
|
return entity.Token{}, ers.ArkInternal("json.Unmarshal token error", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) setToken(ctx context.Context, tx redis.Pipeliner, token entity.Token, body []byte, ttl time.Duration) error {
|
||||||
|
return tx.Set(ctx, domain.GetAccessTokenRedisKey(token.ID), body, ttl).Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) setRefreshToken(ctx context.Context, tx redis.Pipeliner, token entity.Token, ttl time.Duration) error {
|
||||||
|
if token.RefreshToken != "" {
|
||||||
|
return tx.Set(ctx, domain.RefreshTokenRedisKey.With(token.RefreshToken).ToString(), token.ID, ttl).Err()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) setRelation(ctx context.Context, tx redis.Pipeliner, uid, deviceID, tokenID string, ttl time.Duration) error {
|
||||||
|
if err := tx.SAdd(ctx, domain.UIDTokenRedisKey.With(uid).ToString(), tokenID).Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tx.SAdd(ctx, domain.DeviceTokenRedisKey.With(deviceID).ToString(), tokenID).Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) deleteKeys(ctx context.Context, keys ...string) error {
|
||||||
|
return t.store.Pipelined(func(tx redis.Pipeliner) error {
|
||||||
|
for _, key := range keys {
|
||||||
|
if err := tx.Del(ctx, key).Err(); err != nil {
|
||||||
|
return domain.RedisDelError(fmt.Sprintf("store.Del key error: %v", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) getTokensBySet(ctx context.Context, setKey string) ([]entity.Token, error) {
|
||||||
|
ids, err := t.store.Smembers(setKey)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, redis.Nil) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, domain.RedisError(fmt.Sprintf("getTokensBySet store.Get %s error: %v", setKey, err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
|
var tokens []entity.Token
|
||||||
|
var deleteTokens []string
|
||||||
|
now := time.Now().Unix()
|
||||||
|
for _, id := range ids {
|
||||||
|
token, err := t.get(ctx, domain.GetAccessTokenRedisKey(id))
|
||||||
|
if err != nil {
|
||||||
|
deleteTokens = append(deleteTokens, id)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if int64(token.ExpiresIn) < now {
|
||||||
|
deleteTokens = append(deleteTokens, id)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens = append(tokens, token)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(deleteTokens) > 0 {
|
||||||
|
_ = t.DeleteAccessTokenByID(ctx, deleteTokens)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokens, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) getCountBySet(setKey string) (int, error) {
|
||||||
|
count, err := t.store.Scard(setKey)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int(count), nil
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
// Code generated by goctl. DO NOT EDIT.
|
||||||
|
// Source: permission.proto
|
||||||
|
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ark-permission/gen_result/pb/permission"
|
||||||
|
"ark-permission/internal/svc"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PermissionServiceServer struct {
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
permission.UnimplementedPermissionServiceServer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPermissionServiceServer(svcCtx *svc.ServiceContext) *PermissionServiceServer {
|
||||||
|
return &PermissionServiceServer{
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
// Code generated by goctl. DO NOT EDIT.
|
||||||
|
// Source: permission.proto
|
||||||
|
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"ark-permission/gen_result/pb/permission"
|
||||||
|
"ark-permission/internal/logic/roleservice"
|
||||||
|
"ark-permission/internal/svc"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RoleServiceServer struct {
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
permission.UnimplementedRoleServiceServer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRoleServiceServer(svcCtx *svc.ServiceContext) *RoleServiceServer {
|
||||||
|
return &RoleServiceServer{
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *RoleServiceServer) Ping(ctx context.Context, in *permission.OKResp) (*permission.OKResp, error) {
|
||||||
|
l := roleservicelogic.NewPingLogic(ctx, s.svcCtx)
|
||||||
|
return l.Ping(in)
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"ark-permission/gen_result/pb/permission"
|
"ark-permission/gen_result/pb/permission"
|
||||||
"ark-permission/internal/logic"
|
"ark-permission/internal/logic/tokenservice"
|
||||||
"ark-permission/internal/svc"
|
"ark-permission/internal/svc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -24,60 +24,60 @@ func NewTokenServiceServer(svcCtx *svc.ServiceContext) *TokenServiceServer {
|
||||||
|
|
||||||
// NewToken 建立一個新的 Token,例如:AccessToken
|
// NewToken 建立一個新的 Token,例如:AccessToken
|
||||||
func (s *TokenServiceServer) NewToken(ctx context.Context, in *permission.AuthorizationReq) (*permission.TokenResp, error) {
|
func (s *TokenServiceServer) NewToken(ctx context.Context, in *permission.AuthorizationReq) (*permission.TokenResp, error) {
|
||||||
l := logic.NewNewTokenLogic(ctx, s.svcCtx)
|
l := tokenservicelogic.NewNewTokenLogic(ctx, s.svcCtx)
|
||||||
return l.NewToken(in)
|
return l.NewToken(in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RefreshToken 更新目前的token 以及裡面包含的一次性 Token
|
// RefreshToken 更新目前的token 以及裡面包含的一次性 Token
|
||||||
func (s *TokenServiceServer) RefreshToken(ctx context.Context, in *permission.RefreshTokenReq) (*permission.RefreshTokenResp, error) {
|
func (s *TokenServiceServer) RefreshToken(ctx context.Context, in *permission.RefreshTokenReq) (*permission.RefreshTokenResp, error) {
|
||||||
l := logic.NewRefreshTokenLogic(ctx, s.svcCtx)
|
l := tokenservicelogic.NewRefreshTokenLogic(ctx, s.svcCtx)
|
||||||
return l.RefreshToken(in)
|
return l.RefreshToken(in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CancelToken 取消 Token,也包含他裡面的 One Time Toke
|
// CancelToken 取消 Token,也包含他裡面的 One Time Toke
|
||||||
func (s *TokenServiceServer) CancelToken(ctx context.Context, in *permission.CancelTokenReq) (*permission.OKResp, error) {
|
func (s *TokenServiceServer) CancelToken(ctx context.Context, in *permission.CancelTokenReq) (*permission.OKResp, error) {
|
||||||
l := logic.NewCancelTokenLogic(ctx, s.svcCtx)
|
l := tokenservicelogic.NewCancelTokenLogic(ctx, s.svcCtx)
|
||||||
return l.CancelToken(in)
|
return l.CancelToken(in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CancelTokenByUID 取消 Token (取消這個用戶從不同 Device 登入的所有 Token),也包含他裡面的 One Time Toke
|
|
||||||
func (s *TokenServiceServer) CancelTokenByUID(ctx context.Context, in *permission.DoTokenByUIDReq) (*permission.OKResp, error) {
|
|
||||||
l := logic.NewCancelTokenByUIDLogic(ctx, s.svcCtx)
|
|
||||||
return l.CancelTokenByUID(in)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CancelTokenByDeviceID 取消 Token
|
|
||||||
func (s *TokenServiceServer) CancelTokenByDeviceID(ctx context.Context, in *permission.DoTokenByDeviceIDReq) (*permission.OKResp, error) {
|
|
||||||
l := logic.NewCancelTokenByDeviceIDLogic(ctx, s.svcCtx)
|
|
||||||
return l.CancelTokenByDeviceID(in)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidationToken 驗證這個 Token 有沒有效
|
// ValidationToken 驗證這個 Token 有沒有效
|
||||||
func (s *TokenServiceServer) ValidationToken(ctx context.Context, in *permission.ValidationTokenReq) (*permission.ValidationTokenResp, error) {
|
func (s *TokenServiceServer) ValidationToken(ctx context.Context, in *permission.ValidationTokenReq) (*permission.ValidationTokenResp, error) {
|
||||||
l := logic.NewValidationTokenLogic(ctx, s.svcCtx)
|
l := tokenservicelogic.NewValidationTokenLogic(ctx, s.svcCtx)
|
||||||
return l.ValidationToken(in)
|
return l.ValidationToken(in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserTokensByDeviceIDs 取得目前所對應的 DeviceID 所存在的 Tokens
|
// CancelTokens 取消 Token 從UID 視角,以及 token id 視角出發, UID 登出,底下所有 Device ID 也要登出, Token ID 登出, 所有 UID + Device 都要登出
|
||||||
func (s *TokenServiceServer) GetUserTokensByDeviceID(ctx context.Context, in *permission.DoTokenByDeviceIDReq) (*permission.Tokens, error) {
|
func (s *TokenServiceServer) CancelTokens(ctx context.Context, in *permission.DoTokenByUIDReq) (*permission.OKResp, error) {
|
||||||
l := logic.NewGetUserTokensByDeviceIDLogic(ctx, s.svcCtx)
|
l := tokenservicelogic.NewCancelTokensLogic(ctx, s.svcCtx)
|
||||||
return l.GetUserTokensByDeviceID(in)
|
return l.CancelTokens(in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserTokensByUID 取得目前所對應的 UID 所存在的 Tokens
|
// CancelTokenByDeviceId 取消 Token, 從 Device 視角出發,可以選,登出這個Device 下所有 token ,登出這個Device 下指定token
|
||||||
func (s *TokenServiceServer) GetUserTokensByUID(ctx context.Context, in *permission.DoTokenByUIDReq) (*permission.Tokens, error) {
|
func (s *TokenServiceServer) CancelTokenByDeviceId(ctx context.Context, in *permission.DoTokenByDeviceIDReq) (*permission.OKResp, error) {
|
||||||
l := logic.NewGetUserTokensByUIDLogic(ctx, s.svcCtx)
|
l := tokenservicelogic.NewCancelTokenByDeviceIdLogic(ctx, s.svcCtx)
|
||||||
return l.GetUserTokensByUID(in)
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
// NewOneTimeToken 建立一次性使用,例如:RefreshToken
|
||||||
func (s *TokenServiceServer) NewOneTimeToken(ctx context.Context, in *permission.CreateOneTimeTokenReq) (*permission.CreateOneTimeTokenResp, error) {
|
func (s *TokenServiceServer) NewOneTimeToken(ctx context.Context, in *permission.CreateOneTimeTokenReq) (*permission.CreateOneTimeTokenResp, error) {
|
||||||
l := logic.NewNewOneTimeTokenLogic(ctx, s.svcCtx)
|
l := tokenservicelogic.NewNewOneTimeTokenLogic(ctx, s.svcCtx)
|
||||||
return l.NewOneTimeToken(in)
|
return l.NewOneTimeToken(in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CancelOneTimeToken 取消一次性使用
|
// CancelOneTimeToken 取消一次性使用
|
||||||
func (s *TokenServiceServer) CancelOneTimeToken(ctx context.Context, in *permission.CreateOneTimeTokenReq) (*permission.CreateOneTimeTokenResp, error) {
|
func (s *TokenServiceServer) CancelOneTimeToken(ctx context.Context, in *permission.CancelOneTimeTokenReq) (*permission.OKResp, error) {
|
||||||
l := logic.NewCancelOneTimeTokenLogic(ctx, s.svcCtx)
|
l := tokenservicelogic.NewCancelOneTimeTokenLogic(ctx, s.svcCtx)
|
||||||
return l.CancelOneTimeToken(in)
|
return l.CancelOneTimeToken(in)
|
||||||
}
|
}
|
|
@ -1,13 +1,36 @@
|
||||||
package svc
|
package svc
|
||||||
|
|
||||||
import "ark-permission/internal/config"
|
import (
|
||||||
|
"ark-permission/internal/config"
|
||||||
|
"ark-permission/internal/domain/repository"
|
||||||
|
"ark-permission/internal/lib/required"
|
||||||
|
repo "ark-permission/internal/repository"
|
||||||
|
ers "code.30cm.net/wanderland/library-go/errors"
|
||||||
|
"code.30cm.net/wanderland/library-go/errors/code"
|
||||||
|
"github.com/zeromicro/go-zero/core/stores/redis"
|
||||||
|
)
|
||||||
|
|
||||||
type ServiceContext struct {
|
type ServiceContext struct {
|
||||||
Config config.Config
|
Config config.Config
|
||||||
|
|
||||||
|
Validate required.Validate
|
||||||
|
Redis redis.Redis
|
||||||
|
TokenRedisRepo repository.TokenRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServiceContext(c config.Config) *ServiceContext {
|
func NewServiceContext(c config.Config) *ServiceContext {
|
||||||
|
newRedis, err := redis.NewRedis(c.RedisCluster, redis.Cluster())
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
ers.Scope = code.CloudEPPermission
|
||||||
|
|
||||||
return &ServiceContext{
|
return &ServiceContext{
|
||||||
Config: c,
|
Config: c,
|
||||||
|
Validate: required.MustValidator(),
|
||||||
|
Redis: *newRedis,
|
||||||
|
TokenRedisRepo: repo.NewTokenRepository(repo.TokenRepositoryParam{
|
||||||
|
Store: newRedis,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
permissionservice "ark-permission/internal/server/permissionservice"
|
||||||
|
roleservice "ark-permission/internal/server/roleservice"
|
||||||
|
tokenservice "ark-permission/internal/server/tokenservice"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ark-permission/gen_result/pb/permission"
|
"ark-permission/gen_result/pb/permission"
|
||||||
"ark-permission/internal/config"
|
"ark-permission/internal/config"
|
||||||
"ark-permission/internal/server"
|
|
||||||
"ark-permission/internal/svc"
|
"ark-permission/internal/svc"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/conf"
|
"github.com/zeromicro/go-zero/core/conf"
|
||||||
|
@ -26,7 +28,9 @@ func main() {
|
||||||
ctx := svc.NewServiceContext(c)
|
ctx := svc.NewServiceContext(c)
|
||||||
|
|
||||||
s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
|
s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
|
||||||
permission.RegisterTokenServiceServer(grpcServer, server.NewTokenServiceServer(ctx))
|
permission.RegisterTokenServiceServer(grpcServer, tokenservice.NewTokenServiceServer(ctx))
|
||||||
|
permission.RegisterRoleServiceServer(grpcServer, roleservice.NewRoleServiceServer(ctx))
|
||||||
|
permission.RegisterPermissionServiceServer(grpcServer, permissionservice.NewPermissionServiceServer(ctx))
|
||||||
|
|
||||||
if c.Mode == service.DevMode || c.Mode == service.TestMode {
|
if c.Mode == service.DevMode || c.Mode == service.TestMode {
|
||||||
reflection.Register(grpcServer)
|
reflection.Register(grpcServer)
|
||||||
|
@ -34,6 +38,9 @@ func main() {
|
||||||
})
|
})
|
||||||
defer s.Stop()
|
defer s.Stop()
|
||||||
|
|
||||||
|
// 加入中間件
|
||||||
|
// s.AddUnaryInterceptors(middleware.TimeoutMiddleware)
|
||||||
|
|
||||||
fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
|
fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
|
||||||
s.Start()
|
s.Start()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue