I am using Gitlab authentication in my current symfony project. I am using following two packages.
omines/oauth2-gitlab
knpuniversity/oauth2-client-bundle
Inside my security.yaml file
security:
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
app_user_provider:
id: App\Security\UserProvider
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: true
guard:
authenticators:
- App\Security\GitlabAuthenticator
access_control:
- { path: ^/connect, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_USER }
This is working fine and it is storing cookie PHPSESSID. I need to retrieve the username after successful login.
It is very very simple. Just use $this->getUser().
public function index()
{
/** #var \App\Entity\User $user */
$user = $this->getUser();
return new Response('Well hi there '.$user->getFirstName());
}
UserProvider (that's used in login process) returns a UserInterface, which represent a User. From it you can access the username.
Now, how to retrieve that user?
Depending on Symfony version, and depending where you want to access it, you have several possibilities:
Symfony <3.2
In controller -> you can use $this->getUser()->getUsername();
Symfony >=3.2
In controller -> Inject UserInterface directly as a dependency (read more)
For both cases, if you need the user not in controller, you can inject (based on your symfony version) the TokenStorage or the Security service (can't find which version supports which, for sure Security component is supported in sf5).
If you choose (or are forced) to go with TokenStorage (or its interface), you need to perform the following steps:
getToken
check if the token is not null
retrieve the username from the token (or optionally retrieve the whole user and then retrieve the username from there)
Related
I have a question regarding authentication with JWT and Facebook for a restful API app.
I am using Symfony 4 and for authentication "lexik/jwt-authentication-bundle": "^2.6", to generate jwt tokens based on username and password.
Here is my configuration security.yaml:
security:
encoders:
App\Entity\User: bcrypt
providers:
database:
entity:
class: App\Entity\User
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/api/login
stateless: true
anonymous: true
json_login:
check_path: /api/login
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
register:
pattern: ^/api/register
anonymous: true
methods: [POST]
docs:
pattern: ^/api/docs
anonymous: true
methods: [GET]
api:
pattern: ^/api
stateless: true
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
access_control:
- { path: ^/api/docs, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/profile/social-account, roles: ROLE_INFLUENCER }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
I am trying to add also login by facebook but I have no idea how to handle that with JWT, as I want to return after login a JWT token.
Is there any way to handle facebook login and JWT login?
You can have a good idea of how to implement it here : https://github.com/lexik/LexikJWTAuthenticationBundle/issues/295.
Basically after the user accept the Facebook login on your frontend :
send a POST request with the user's token to your custom endpoint (for example login/facebook.
Then you can make an extra request with the user's token to Facebook api to get extra information as firstname, lastname or user's email (for example with https://graph.facebook.com/me/?fields=first_name,last_name,email).
The token needs to have correct permissions to get access to those information (https://developers.facebook.com/docs/facebook-login/permissions/overview).
You can now create a user if the email is not in your database.
Finally just return the token with create method of JWTManager class.
$token = $this->jwtManager->create($user);
By using this logic, it is totally transparent for your frontend whether your user has already loged in with your app or not and it gets a token the same way a user would get with your /login endpoint.
I assume you have an frontend application (React/Angular/Vue...) that consumes your API.
I would handle the "login with Facebook" on the Frontend side. After the user accepts the authentication via Facebook, they will be send back to your frontend app. At that point you have access to all the information you need (e.g. e-mail, first name, last name, etc).
POST that information to a new endpoint (e.g. /api/facebook-login), which handles your registration and/or login process, and then return an JWT token with your newly created user. Lexik makes it possible to manually create tokens:
class ApiController extends Controller
{
public function getTokenUser(UserInterface $user, JWTTokenManagerInterface $JWTManager)
{
// ...
return new JsonResponse(['token' => $JWTManager->create($user)]);
}
}
I am trying to create a hybrid api-token/form login security using Symfony's (2.8.24) guard mechanism.
My security.yml looks like this:
security:
acl:
connection: default
providers:
jwt:
id: app.jwt_user_provider
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
guard:
entry_point: app.jwt_authenticator
authenticators:
- app.jwt_authenticator
- app.authenticator.form_login
provider: jwt
access_control:
- { path: ^/general/info, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, role: IS_AUTHENTICATED_FULLY }
So I have a main firewall with two configured authenticators. The entry point is the app.jwt_authenticator, with a fallback to the app.authenticator.form_login.
I want it so that when no token is present, that the app.jwt_authenticator is skipped.
The getCredentials() method of the app.jwt_authenticator looks like this basically:
public function getCredentials(Request $request): ?string
{
$tokenString = $request->headers->get('Authorization');
if (!$tokenString) {
$this->logger->warn('No authorization header');
return null;
}
return $tokenString;
}
So if there is no Authorization header it returns null.
And according to Symfony's documentation:
Get the authentication credentials from the request and return them as
any type (e.g. an associate array). If you return null, authentication
will be skipped.
So I would expect this authenticator to be skipped when there is no Authorization header, but unfortunately that is not the case.
Even though getCredentials() returns null (and I have verified that it does), the start() method gets called instead of skipping this authenticator and moving on to the next.
Is my configuration not correct? Am I misunderstanding the mechanism?
What do I need to do to implement this hybrid?
It turns out the trick was to change the entrypoint to app.authenticator.form_login
I am developing a backend service for my own project with Symfony2. What i would like to do is simple user registration. Whenever a user needs to be created there will be a POST call to
/v1.0/users (with POST method)
I would like to create a new user. For all of the other url should be authenticated except this one. So I created UserProvider and UserAuthenticator as described in here : http://symfony.com/doc/current/cookbook/security/api_key_authentication.html
I created a secured area and it works fine, but i want to disable this firewal for the url above with post method. I couldnt figure it out how. Here is my security.yml file
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
api_user_secured_area:
pattern: ^/v1.0/users
stateless: true
simple_preauth:
authenticator: user_token_authenticator
provider: user_token_provider
access_control:
...
user_register:
path: /v1.0/users
roles: IS_AUTHENTICATED_ANONYMOUSLY ?? FOR POST ONLY ??
PS: I dont want to use annotation for security (like #Security in the controller)
Access control can be filtered to a given METHOD using the Methods property, please see here for more filters/options regarding access control:
http://symfony.com/doc/current/cookbook/security/access_control.html
Here is the option integrated into your code:
access_control:
user_register:
path: /v1.0/users
methods: [ POST ]
roles: IS_AUTHENTICATED_ANONYMOUSLY
In this case, after a successful login, I need to update the user's login time into the underlying table.
The User entity currently implements UserInterface and is doing fine. Just want to add some extra code to log the login date time of the user.
Searched the site and seemed to me to use an EventListener etc is a bit heavy. Other lighter alternatives?
You can implement a Success Hander.
Write a class that implement the AuthenticationSuccessHandlerInterface:
Define it as a service (you can inject other services like doctrine
or the security context, in your case the Session)
Add the handler service in the security config like:
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
secured_area:
pattern: ^/
anonymous: ~
form_login:
login_path: login
check_path: login_check
success_handler: some.service.id
logout:
path: logout
target: /
Check this for a complete example and the reference doc for all the symfony2 security configuration options (you can configure the failure_handler also).
In my working solutions I implements the method onSecurityInteractiveLogin in my listener as:
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
$user = $event->getAuthenticationToken()->getUser();
$user->setLastLogin(new \Datetime());
// Entity manager injected by container in the service definition
$this->em->persist($user);
$this->em->flush();
}
Hope this help
I would have liked in Symfony2 "v2.1" a page that can be accessed without authentication and Authenticated.
I used the anonymous, but here is a token of the Authenticated User Anonymous and not be proper token.
Does anyone have a solution
As mentioned in the security:
Anonymous users are technically authenticated, meaning that the
isAuthenticated() method of an anonymous user object will return true.
//if you want myPage to be accessible by everyone
security:
firewalls:
secured_area:
pattern: ^/
anonymous: ~
access_control:
- { path: ^/myPage, roles: IS_AUTHENTICATED_ANONYMOUSLY }
If you remove the anonymous key, the firewall will always make a user fully authenticate immediately.