-
-
Notifications
You must be signed in to change notification settings - Fork 614
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature] Usage for isolated services (no user DB access) #277
Comments
Hi @scaytrase, Fortunately, the fact we use Guard should help here, compared to our v1 were we used a classic listener. The Guard authenticator which makes use of the configured user provider is extensible. What I don't get here is that for being authenticated, you need an implementation of Anyway, if I understand your need correctly, here is the way I would do proceed:
Note that this line must appear in your Another alternative could be to just write a custom user provider, declare it in configuration and specify it in the firewall mapping. The provider I have to mention that in an authentication context, we encourage to favor hitting a datastore rather than the storing sensible data in the jwt, such as user roles which can be changed at any time, the jwt would keep the old roles until expiration thus potentially give access to resources that it shouldn't. Please keep us informed if you think such should be easier to achieve or if you're fine with the proposed alternatives. |
As far as I see the implementation of As for hitting the datastore, the my understanding exactly the same, that mentioned on the official jwt.io website:
So the only time we need to hit a DB is a generation moment. All other times we can use the "cached" information. Yes, as the other caches we need to understand the ways of invalidation of data, but this is another side of question. If we hit the Auth DB each time we get a request - there is really no need with such complex things as JWT as soon as we can regenerate the whole JWT content from the DB hits. And the token itself can be replaced with any kind of bearer token (i.e. signed timestamp) |
So the general idea, as a feature request, is to do the following:
As a bonus, allowing bootstrap with just configuration of bundle
The everything else looks like already working, like having only pubkey configured |
Yeah, it's required by the symfony security component to have a configured user provider for securing resources, and this bundle uses the security component. About the |
Thank you for the hints. I'm more thinking about something like:
So you would just have to make your User class extend the security:
providers:
jwt_user_provider:
lexik_jwt:
class: AppBundle\YourJWTUser Using it in your jwt-protected firewall and create the |
Sounds good for the brief look. Can you provide the sample implementation of |
See #278 |
I don't see much value in making the |
If we speak about using the single algorythm alongside the coupled system - yes, there is no need to configure the I agree, that hardcoded |
@scaytrase The
It can be achieved by hooking on the |
It should be, but user providers do not always use
Let's take FOSUserBundle (which is most of the times used with this bundle), the
Either I misunderstand or I totally don't agree here. Why should every user-related key in the payload be configurable? And why should hardcoding the name of a payload key be prohibited? I really don't see any issue, things should be configurable only if there is a real interest, otherwise let's just be consistent with the Again, If someone needs to change that key then he can just listen on the good event and change it, as any other key of the payload. |
So, you are breaking the single responsibility principle here. Your code is neither responsible for fetching You are missing the some methods on
For this purpose there is a method called All the logic working with how to fetch user by username (there is no matter email, login, etc, but username from any kind of login form or api), how to relfresh this user is incapsulated in So you really do not need to know, which field is used to store the username. As I already mentioned above - there can be a situation when such field event does not exist. But you can still write a So if you decouple your processing flows and re-use the build-in mechanics, the |
@scaytrase I know the security component and what it provides, you don't get my point. // form_login authentication succeeded, let's create and return the token
$token = $jwtManager->create($user);
// Assuming we don't have the user_identity_field, the manager would do:
// payload = ['username' => $user->getUsername()];
// Now the user hits the api firewall with the token, let's authenticate it
$payload = $jwtManager->decode($token);
// we don't have to (and can't) use refreshUser here, we don't have access to
// an user instance since the authentication is stateless in all cases,
// but only the value of UserInterface::getUsername() previously put in the token
$user = $userProvider->loadUserByUsername($payload['username']); Here, if the configured user provider is the This bundle doesn't provide user management but only authentication, until here we don't know which user provider will be used and the I made an example where the option must be set to make it work, using this bundle in combination with the So yes, this part of the code base is not sexy, but we need it actually. Of course, If you find a way to make it work without the option, I would be happy to see how it look in a PR. |
No offence, I've just responded what I've seen :) I've just perform some digging about using emails with FOSUB and seems that the idea you trying to overcome is initially broken See some links:
It's broken by design. The UserProvider you've linked has a significant drawback - it can login BOTH by username and by email, so there is not difference, whether to place a email or username there (so you can do It looks like the architectural drawback of the FOSUB which they cannot handle now (as far as I've understood the comments). If you really want to support this, the better solution is to add some kind of compatibility (bridge?) layer for FOSUB only.
But still, regarding FOSUB, leaving processing incapsulated should work The thing I cannot understand, where the answer |
Well, actually the given example breaks the Says that fixing this making work without any additional configurations.
So everyhing is about conforming the contract |
Of course and thanks a lot for the time spent here at trying to make this better, it's much appreciated.
I already realized it but Indeed, the links you given confirm it. That's why I finally took the
To be honest I don't expect much since I tried to dig into it already, but at worst it'll make you understand why our code contains such weird things, at best you'll find what we are missing and help avoiding that stuff in our code, so thanks for looking at it.
Oops, looks like a leftover from my tests.
Getting back to the original discussion, I finally think it's legit to make the |
From jwt.io: > Self-contained: The payload contains all the required information about the user, avoiding the need to query the database more than once. This is a working draft at the moment, allowing to preserve the federation benefit of JWT by avoiding fetching the user from the datastore more than once, so each token-authenticated request trusts in the JWT data rather than reloading the user to authenticate it. I'm not sure how this should be introduced, at first I think it should not be the recommended way to use this bundle, but I do think we should have it since we are signing tokens and verifying them at each request, it makes sense to don't reverify the user. Closes #277 once finished. /cc @scaytrase
Is possible to use this bundle as an authentication system for isolated services, which do not have the access to the user DB to reload the user data.
We can sign all the needed data (username, roles, som other payload) to the JWT, so on the isolited side we only need a public key to check the signature and once it is OK we can use the token as a trusted store of user information for
UserInteface
As far as I can understand, currently the bundle uses the
UserProvider
via Guard and there is no documented way to bypass it?The text was updated successfully, but these errors were encountered: