gakhov
gakhov

Reputation: 1971

Managing user access to pages in Symfony2

I'm working on managing access for users to some pages on my site. I have 1 type of fully authenticated users (role: ROLE_MEMBER, based on ROLE_USER) and, of course, anonymous users too.

Let's say I have 2 pages (/index, /account) on the site, both with secure: true. Let's say /index requires role: IS_AUTHENTICATED_ANONYMOUSLY and /account requires role: IS_AUTHENTICATED_FULLY (for ROLE_MEMBER).

I want to show special "account menu" for logged in members on both pages, so in template i check is_granted('ROLE_MEMBER').

That works great for /account, of course. The problem, when member is navigated to /index (which is "anonymous" page) function is_granted('ROLE_MEMBER') returns 0, and is_granted('IS_AUTHENTICATED_ANONYMOUSLY') returns 1. When members navigates to /account again, everything works without reentering password (that means member still not logged out).

So, the question is how to detect what member is logged in user inside template for /index page?

UPDATED. @alessandro1997 here is my app/config/security.yml configuration

security:
    encoders:
        AG\MemberBundle\Entity\Member:
            id: member_saltedpassword_encoder

    role_hierarchy:
        ROLE_MEMBER: ROLE_USER
        ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_MEMBER, ROLE_ALLOWED_TO_SWITCH]

    providers:
        member_db:
            entity: { class: AGMemberBundle:Member, property: email }

    firewalls:
        members:
            pattern:  ^/account
            security: true
            form_login: 
                login_path: /account/login
                check_path: /account/login/check
                post_only: true
                username_parameter:  _email
                password_parameter:  _password
                default_target_path: /account/
                always_use_default_target_path: true
                # csrf token options
                csrf_parameter: _csrf_token
                intention: authenticate
            provider: member_db
            logout:
                path: /account/logout
                target: /
            remember_me:
                key:      "qwewqeqwerwxeweqweqwe"
                lifetime: 3600
                path:     /
                domain:   ~ # Defaults to the current domain from $_SERVER
        pages:
            pattern: ^/
            security: true
            anonymous: ~

    access_control:
        - { path: ^/account, roles: IS_AUTHENTICATED_FULLY }
        - { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }

Upvotes: 0

Views: 2514

Answers (2)

thorinkor
thorinkor

Reputation: 966

It's happening because You are using two separate firewalls and You authenticate user only to one firewall - they are completely separate security systems. You should set up only one firewall and use access_control with diffrent roles signed.

I've had very similar problem - check it out here -> Symfony 2 - firewall and access control issue

Upvotes: 1

thorinkor
thorinkor

Reputation: 966

I think it might be a problem with:

access_control:
    - { path: ^/account, roles: IS_AUTHENTICATED_FULLY }
    - { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }

First you're setting the access to /account, and then you override it with access to index path: / . I think it might be ok if you will swap it. Besides I believe there is no point in using access control for user who is authenticated_annonymously. Use that instead:

access_control:
    - { path: ^/account, roles: IS_AUTHENTICATED_FULLY }

Another problem is that login and login_check are hidden behind the firewall - user who will try to log in will not be able to see the login page, as you have set the /account path only for fully authenticated users and now:

form_login: 
            login_path: /account/login
            check_path: /account/login/check

I believe it should work with something like that:

    firewalls:
          login_firewall: 
              pattern:    ^/account/login$
              anonymous:  ~
    access_control:
    - { path: ^/account, roles: IS_AUTHENTICATED_FULLY }
    - { path: ^/account/login, roles: IS_AUTHENTICATED_ANONYMOUSLY}
    - { path: ^/account/login_check, roles: IS_AUTHENTICATED_ANONYMOUSLY}

However, in my app, I just took the login and login_check paths out of the /account, so the security.yml looks like that:

security:
firewalls:
    login_firewall: 
        pattern:    ^/login$
        anonymous:  ~
    secured_area:
        pattern:    ^/
        form_login:
            login_path:  /login
            check_path:  /login_check
            always_use_default_target_path: true
            default_target_path: /
        logout:
            path:   /logout
            target: /

providers:
    main:
        entity: { class: Core\UserBundle\Entity\User, property: username }
encoders:
    Core\UserBundle\Entity\User: 
        algorithm:   sha256
        iterations: 10
        encode_as_base64: true
access_control:
    - { path: ^/admin, roles: ROLE_SUPERADMIN }
    - { path: ^/user, roles: ROLE_USER }
    - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }

I'm not a Symfony expert and it might not be the perfect solution, but I hope that helps ;)

Upvotes: 0

Related Questions