I'm implementing a Symfony 2 solution according to a set specification. The specification states that the login form at GET /login must resumbit to POST /login.
How can I change the URL for the /login_check? Can I create a route that calls the security controller directly, like the following? I don't see any controller in the Security bundle.
oft_auth_login:
pattern: /login
defaults: { _controller: MagicSecurityBundle:Default:login_check }
methods: [POST]
According to the documentation for security.yml,
check_path (type: string, default: /login_check) This is the route or path that your login form must submit to. The firewall will intercept any requests (POST requests only, by default) to this URL and process the submitted login credentials.
So I have to create a valid route, but I can't figure out where it's supposed to point to (firewall action? security action?) or what it's supposed to do.
I changed it to POST /login, but it said it couldn't find it...
Now I have a security.yml file that looks like this:
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/login$
security: false
secured_area:
pattern: ^/
anonymous: ~
form_login:
login_path: oft_auth_login
check_path: oft_auth_login_check
username_parameter: user
password_parameter: passwd
And a routing.yml that looks like this:
oft_auth_login:
pattern: /login
defaults: { _controller: OftAuthBundle:Default:login }
methods: [GET]
oft_auth_login_check:
pattern: /login
methods: [POST]
I can load the form fine (GET /login), and the form method is POST and the action is /login, but when I submit it, I get the following error (404, route not found):
Unable to find the controller for path "/login". Maybe you forgot to add the matching route in your routing configuration? 404 Not Found - NotFoundHttpException
What code, firewall methods, etc. would I have to call to authenticate a user in a custom check_login method, or any other way to accomplish what I'm trying to do, which is to access and post the login form to the same URL (/login)?
In your security.yml, you should see something like:
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/login$
security: false
main:
pattern: ^/
form_login:
check_path: /login_check
login_path: /login
always_use_default_target_path: true
default_target_path: /secured
In your routing.yml, you should see something like:
## Security Routes
default:
pattern: /
defaults: { _controller: SecurityBundle:Security:login }
login:
pattern: /login
defaults: { _controller: SecurityBundle:Security:login }
login_check:
pattern: /login_check
logout:
pattern: /logout
Change check_path: /login_check
in security.yml to check_path: /new_login_check
Change pattern: /login_check
in routing.yml to pattern: /new_login_check
That will change the URL for the login check route.
Your login form probably looks like:
<form action="{{ path('login_check') }}" method="post" class="form-horizontal">
The {{ path('login_check') }}
twig snippet outputs the URL to the route identified by login_check
. This is not the same as a URL. Example routing configuration (using YAML):
route_identifier:
pattern: /relative/url/path
defaults: {_controller: ExampleBundle:Example:test}
Using the path('route_identifier') function will route to the URL /relative/URL/path, which calls the method testAction in the ExampleController class in the ExampleBundle.
You should always use Symfony's routing where possible in your templates, so you avoid conflicts and can easily change routes.
Somewhat orthogonal to changing the login check route, but rereading your question, it says that you want to use the /login path for different actions depending on GET/POST. This requires an extra step, as Symfony will choose the first matching route available to use.
After following the above, your routing.yml might contain something like:
## Security Routes
default:
pattern: /
defaults: { _controller: SecurityBundle:Security:login }
login:
pattern: /login
defaults: { _controller: SecurityBundle:Security:login }
login_check:
pattern: /login
logout:
pattern: /logout
As such, it'll only ever match the login route, never the login_check route. You'll need to specify a method as well:
## Security Routes
default:
pattern: /
defaults: { _controller: SecurityBundle:Security:login }
login:
pattern: /login
defaults: { _controller: SecurityBundle:Security:login }
methods: [GET]
login_check:
pattern: /login
methods: [POST]
logout:
pattern: /logout
See the Symfony documentation on Routing for more information.
Another issue you will run into is that the login_check route must match the firewall the user is logging into, but the login route must be accessible to non-authenticated users!
From Symfony's documentation:
Next, make sure that your check_path URL (e.g. /login_check) is behind the firewall you're using for your form login (in this example, the single firewall matches all URLs, including /login_check). If /login_check doesn't match any firewall, you'll receive a Unable to find the controller for path "/login_check" exception.
This is a bit tricky when using the same URL for both actions, but it is possible. The biggest hurdle is that you can't match firewalls by an http method. The first thing you need to do, then, is make sure that both login routes only match your main firewall, by removing any firewalls that specifically match the login routes.
In the example above, that means removing this section from the security.yml:
login:
pattern: ^/login$
security: false
That'll meet the first requirement of login_check matching the firewall you're using, but unauthenticated users won't be able to reach the login route any more! That causes a redirect loop. Fortunately, there's a way around that. In your security.yml file, below the section firewalls, you should see a section called access_control. (If not, make one.) You'll need to add the following line to the top of this section. (Again, Symfony matching is conservative, quitting once it finds the first match.)
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, methods: [GET] }
That will explicitly allow anonymous users to access the /login path, but only via GET.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With