github.com/annwntech/go-micro/v2@v2.9.5/auth/service/service.go (about) 1 package service 2 3 import ( 4 "context" 5 "strings" 6 "time" 7 8 "github.com/annwntech/go-micro/v2/auth" 9 "github.com/annwntech/go-micro/v2/auth/rules" 10 pb "github.com/annwntech/go-micro/v2/auth/service/proto" 11 "github.com/annwntech/go-micro/v2/auth/token" 12 "github.com/annwntech/go-micro/v2/auth/token/jwt" 13 "github.com/annwntech/go-micro/v2/client" 14 ) 15 16 // svc is the service implementation of the Auth interface 17 type svc struct { 18 options auth.Options 19 auth pb.AuthService 20 rules pb.RulesService 21 jwt token.Provider 22 } 23 24 func (s *svc) String() string { 25 return "service" 26 } 27 28 func (s *svc) Init(opts ...auth.Option) { 29 for _, o := range opts { 30 o(&s.options) 31 } 32 33 if s.options.Client == nil { 34 s.options.Client = client.DefaultClient 35 } 36 37 s.auth = pb.NewAuthService("go.micro.auth", s.options.Client) 38 s.rules = pb.NewRulesService("go.micro.auth", s.options.Client) 39 40 // if we have a JWT public key passed as an option, 41 // we can decode tokens with the type "JWT" locally 42 // and not have to make an RPC call 43 if key := s.options.PublicKey; len(key) > 0 { 44 s.jwt = jwt.NewTokenProvider(token.WithPublicKey(key)) 45 } 46 } 47 48 func (s *svc) Options() auth.Options { 49 return s.options 50 } 51 52 // Generate a new account 53 func (s *svc) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, error) { 54 options := auth.NewGenerateOptions(opts...) 55 56 rsp, err := s.auth.Generate(context.TODO(), &pb.GenerateRequest{ 57 Id: id, 58 Type: options.Type, 59 Secret: options.Secret, 60 Scopes: options.Scopes, 61 Metadata: options.Metadata, 62 Provider: options.Provider, 63 }) 64 if err != nil { 65 return nil, err 66 } 67 68 return serializeAccount(rsp.Account), nil 69 } 70 71 // Grant access to a resource 72 func (s *svc) Grant(rule *auth.Rule) error { 73 access := pb.Access_UNKNOWN 74 if rule.Access == auth.AccessGranted { 75 access = pb.Access_GRANTED 76 } else if rule.Access == auth.AccessDenied { 77 access = pb.Access_DENIED 78 } 79 80 _, err := s.rules.Create(context.TODO(), &pb.CreateRequest{ 81 Rule: &pb.Rule{ 82 Id: rule.ID, 83 Scope: rule.Scope, 84 Priority: rule.Priority, 85 Access: access, 86 Resource: &pb.Resource{ 87 Type: rule.Resource.Type, 88 Name: rule.Resource.Name, 89 Endpoint: rule.Resource.Endpoint, 90 }, 91 }, 92 }) 93 94 return err 95 } 96 97 // Revoke access to a resource 98 func (s *svc) Revoke(rule *auth.Rule) error { 99 _, err := s.rules.Delete(context.TODO(), &pb.DeleteRequest{ 100 Id: rule.ID, 101 }) 102 103 return err 104 } 105 106 func (s *svc) Rules(opts ...auth.RulesOption) ([]*auth.Rule, error) { 107 var options auth.RulesOptions 108 for _, o := range opts { 109 o(&options) 110 } 111 if options.Context == nil { 112 options.Context = context.TODO() 113 } 114 115 rsp, err := s.rules.List(options.Context, &pb.ListRequest{}, client.WithCache(time.Second*30)) 116 if err != nil { 117 return nil, err 118 } 119 120 rules := make([]*auth.Rule, len(rsp.Rules)) 121 for i, r := range rsp.Rules { 122 rules[i] = serializeRule(r) 123 } 124 125 return rules, nil 126 } 127 128 // Verify an account has access to a resource 129 func (s *svc) Verify(acc *auth.Account, res *auth.Resource, opts ...auth.VerifyOption) error { 130 var options auth.VerifyOptions 131 for _, o := range opts { 132 o(&options) 133 } 134 135 rs, err := s.Rules(auth.RulesContext(options.Context)) 136 if err != nil { 137 return err 138 } 139 140 return rules.VerifyAccess(rs, acc, res) 141 } 142 143 // Inspect a token 144 func (s *svc) Inspect(token string) (*auth.Account, error) { 145 // try to decode JWT locally and fall back to srv if an error occurs 146 if len(strings.Split(token, ".")) == 3 && s.jwt != nil { 147 return s.jwt.Inspect(token) 148 } 149 150 // the token is not a JWT or we do not have the keys to decode it, 151 // fall back to the auth service 152 rsp, err := s.auth.Inspect(context.TODO(), &pb.InspectRequest{Token: token}) 153 if err != nil { 154 return nil, err 155 } 156 return serializeAccount(rsp.Account), nil 157 } 158 159 // Token generation using an account ID and secret 160 func (s *svc) Token(opts ...auth.TokenOption) (*auth.AuthToken, error) { 161 options := auth.NewTokenOptions(opts...) 162 163 rsp, err := s.auth.Token(context.Background(), &pb.TokenRequest{ 164 Id: options.ID, 165 Secret: options.Secret, 166 RefreshToken: options.RefreshToken, 167 TokenExpiry: int64(options.Expiry.Seconds()), 168 }) 169 if err != nil { 170 return nil, err 171 } 172 173 return serializeToken(rsp.Token), nil 174 } 175 176 func serializeToken(t *pb.Token) *auth.AuthToken { 177 return &auth.AuthToken{ 178 AccessToken: t.AccessToken, 179 RefreshToken: t.RefreshToken, 180 Created: time.Unix(t.Created, 0), 181 Expiry: time.Unix(t.Expiry, 0), 182 } 183 } 184 185 func serializeAccount(a *pb.Account) *auth.Account { 186 return &auth.Account{ 187 ID: a.Id, 188 Secret: a.Secret, 189 Issuer: a.Issuer, 190 Metadata: a.Metadata, 191 Scopes: a.Scopes, 192 } 193 } 194 195 func serializeRule(r *pb.Rule) *auth.Rule { 196 var access auth.Access 197 if r.Access == pb.Access_GRANTED { 198 access = auth.AccessGranted 199 } else { 200 access = auth.AccessDenied 201 } 202 203 return &auth.Rule{ 204 ID: r.Id, 205 Scope: r.Scope, 206 Access: access, 207 Priority: r.Priority, 208 Resource: &auth.Resource{ 209 Type: r.Resource.Type, 210 Name: r.Resource.Name, 211 Endpoint: r.Resource.Endpoint, 212 }, 213 } 214 } 215 216 // NewAuth returns a new instance of the Auth service 217 func NewAuth(opts ...auth.Option) auth.Auth { 218 options := auth.NewOptions(opts...) 219 if options.Client == nil { 220 options.Client = client.DefaultClient 221 } 222 223 return &svc{ 224 auth: pb.NewAuthService("go.micro.auth", options.Client), 225 rules: pb.NewRulesService("go.micro.auth", options.Client), 226 options: options, 227 } 228 }