feat: [#478] The guard driver of Auth support custom driver#959
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #959 +/- ##
==========================================
+ Coverage 69.15% 69.31% +0.16%
==========================================
Files 157 160 +3
Lines 10526 10713 +187
==========================================
+ Hits 7279 7426 +147
- Misses 2913 2951 +38
- Partials 334 336 +2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Thanks, checking |
hwbrzzl
left a comment
There was a problem hiding this comment.
Great PR 👍 Could you add some usages in the description? It's better to understand how to use the latest logic.
|
Thanks for your feedback. I'll work on these changes requested. The idea is to create multiple auth drivers and user providers and decouple them from each other. So we could use it any combination. |
|
The existing func (a *JwtGuard) Refresh() (token string, err error) {
auth, ok := a.ctx.Value(ctxKey).(Guards)
if !ok || auth[a.guard] == nil {
return "", errors.AuthParseTokenFirst
}
guard, ok := auth[a.guard]
if !ok {
return "", errors.AuthParseTokenFirst
}
if guard.Claims == nil {
return "", errors.AuthParseTokenFirst
}
nowTime := carbon.Now()
refreshTtl := a.config.GetInt("jwt.refresh_ttl")
if refreshTtl == 0 {
// 100 years
refreshTtl = 60 * 24 * 365 * 100
}
expireTime := carbon.FromStdTime(guard.Claims.ExpiresAt.Time).AddMinutes(refreshTtl)
if nowTime.Gt(expireTime) {
return "", errors.AuthRefreshTimeExceeded
}
token, err = a.LoginUsingID(guard.Claims.Key)
if err != nil {
return "", err
}
return
}This is the new approach with code reuse in mind func (r *JwtGuard) Refresh() (token string, err error) {
guard, err := r.GetAuthToken()
if err != nil {
return "", err
}
nowTime := carbon.Now()
refreshTtl := r.config.GetInt("jwt.refresh_ttl")
if refreshTtl == 0 {
// 100 years
refreshTtl = 60 * 24 * 365 * 100
}
expireTime := carbon.FromStdTime(guard.Claims.ExpiresAt.Time).AddMinutes(refreshTtl)
if nowTime.Gt(expireTime) {
return "", errors.AuthRefreshTimeExceeded
}
token, err = r.LoginUsingID(guard.Claims.Key)
if err != nil {
return "", err
}
return
}
func (r *JwtGuard) GetAuthToken() (*AuthToken, error) {
guards, ok := r.ctx.Value(ctxKey).(Guards)
if !ok {
return nil, ErrorParseTokenFirst
}
return r.authToken(guards)
}
func (r *JwtGuard) authToken(guards Guards) (*AuthToken, error) {
guard, ok := guards[r.guard]
if !ok || guard == nil {
return nil, ErrorParseTokenFirst
}
if guard.Claims == nil {
return nil, errors.AuthParseTokenFirst
}
if guard.Claims.Key == "" {
return nil, errors.AuthInvalidKey
}
if guard.Token == "" { // <-- Since reusing the code, checking the token is required for other func
return nil, errors.AuthTokenExpired
}
return guard, nil
} |
hwbrzzl
left a comment
There was a problem hiding this comment.
Thanks! Almost complete.
There was a problem hiding this comment.
So sorry, I made a mistake here. Given we will implement the session driver in the future, the test cases will be used for both jwt and session drivers. Hence, the single jwt_guard_test.go is unnecessary, we can only keep the auth_test.go file. Could you please move this file back to auth_test.go?
There was a problem hiding this comment.
No problem @hwbrzzl
I realize there's a lot involved, and I'm grateful for your patient and seamless approach.
What about the parsing, refresh func tests?
The session driver does not have Token. We assert the in many places.
These might be not be compatible for the session driver.
There was a problem hiding this comment.
Thanks, about the test cases for the session driver, we can optimize them when implementing it.
There was a problem hiding this comment.
For now, we can just move jwt_guard_test.go back.
hwbrzzl
left a comment
There was a problem hiding this comment.
Amazing PR, thanks 👍 I'll add you to the contributor list. And I'm looking forward to your next feature PR, you will become our core contributor. 💥
Thank you so much, @hwbrzzl , for your incredible patience and guidance throughout this process. I really appreciate your thorough reviews, helpful suggestions, and calm demeanor, even when I was stuck. I learned a lot from you, and I'm very grateful for your support in getting this PR merged. |
|
Could you update the description based on the latest logic? |
|
I think we might need to update the |
|
Yes, please create a PR for goravel/goravel. |
…an commands
Introduces a parameter-less WithCommandsFilter callback on
ApplicationBuilder that returns the positive list of command
signatures to keep when the framework registers its own Artisan
commands. The list is captured once at Build() time and applied to
both the framework's defaultCommands batch and the
console/console/* batch registered by console.ServiceProvider.
Matching rules (signature-only, no category matching):
- exact match (no wildcard) -> command.Signature()
- glob match (entry contains '*') -> command.Signature() via
path.Match ('?' is a literal character)
Semantics:
- method not called -> keep every command (default)
- callback returns nil -> keep every command (no filter)
- callback returns []string{} -> drop every command
- callback returns entries -> keep only matching commands
The filter also trims the user-added commands registered via
WithCommands, so the user cannot bypass the filter by adding
commands.
Closes goravel/goravel#959
…an commands (#1500) * feat: [#959] add WithCommandsFilter builder to scope registered Artisan commands Introduces a parameter-less WithCommandsFilter callback on ApplicationBuilder that returns the positive list of command signatures to keep when the framework registers its own Artisan commands. The list is captured once at Build() time and applied to both the framework's defaultCommands batch and the console/console/* batch registered by console.ServiceProvider. Matching rules (signature-only, no category matching): - exact match (no wildcard) -> command.Signature() - glob match (entry contains '*') -> command.Signature() via path.Match ('?' is a literal character) Semantics: - method not called -> keep every command (default) - callback returns nil -> keep every command (no filter) - callback returns []string{} -> drop every command - callback returns entries -> keep only matching commands The filter also trims the user-added commands registered via WithCommands, so the user cannot bypass the filter by adding commands. Closes goravel/goravel#959 * refactor: address PR #1500 review comments - Rename ConsoleCommandsFilter() -> CommandsFilter() (contract, impl, tests, mocks) - Rename consoleCommandsFilter -> commandsFilter (field name) - Simplify WithCommandsFilter docstrings and clarify ? behavior - Replace .Maybe() with explicit .Once() in service provider tests - Remove duplicate TestDefaultCommandsUpDownBySignature test - Add comment on console.Application.Register clarifying filtering is caller's responsibility * fix: centralize command filtering in registerCommands() Move FilterCommandsByAllowlist into registerCommands() so ALL callers (defaultCommands, configureCommands, Commands()) go through the same gate. Remove redundant filtering from defaultCommands() and simplify configureCommands() to use registerCommands(). Update tests to verify filtering through the Commands() path. * optimize --------- Co-authored-by: Bowen <hwbrzzl@gmail.com>
📑 Description
Closes goravel/goravel#478
Add support to custom Auth drivers and decouple the user provider.
This requires some changes in the config and the Auth library signature.
Config
contract/auth
✅ Checks