Check session variable before delivering cached page

Hi,

I have a custom plugin that is subscribed to this event: Enlight_Controller_Action_PreDispatch_Frontend

Inside the handler function I’m just checkking in the session if there is a variable set. If it is, no action is taken. If it is not, then a page redirect happens to show the user the page that contains the form, which when submitted sets the session variable. It all works fine when in development mode, the problem starts when page is in production mode and pages are shown from cache. Then the session check is skipped.

 

Is there a way to trigger the session checking for the variable before the cached version of the site is delievered?

Thank you for any ideas.

Hello,

You need to read this article.  Shopware take html page from cache for pages, which described in this article.

Can you describe what exactly you want to do?

Some pages aren’t cached at all like account or checkout.

 

For example you can check:

engine/Library/Enlight/View/Default.php::222

assign function contain third parameter where you can set flag - should/shouldn’t variable be cached.

Also you can create frontend widget. Widget will be handle separately.

thank you for your answer @odessite‍ .

All I want to do is make sure that for EVERY request (no matter if the page user wants to visit is cached or not) there is a simple check before that just looks at the session and checks if a certain variable is set. If that variable is set, we’re good to go, user can see the page (from cache or not). If the variable is not set, the user should be redirected to a „custom login“ page where he can submit a form that will in turn set that variable in the session.

The current implementation already does that, BUT it only works in development mode and the code for checking the session variable is not invoked on requests with production mode turned on (whenever a page is delievered from cache).

Do you think implementing it as a widget can solve that?

 

thank you for your help!

>All I want to do is make sure that for EVERY request (no matter if the page user wants to visit is cached or not) there is a simple check before that just looks at the session and checks if a certain variable is set.

It is impossible, in case page is cached - request fetched cached data without handling.

>If the variable is not set, the user should be redirected to a „custom login“ page where he can submit a form that will in turn set that variable in the session.

Is it some specific page?

Is it some specific customer groups?

Can you describe more details, maybe I can propose some solution.

>Do you think implementing it as a widget can solve that?

No, for such cases widget isn’t solution.

Hey, thank you for your help @odessite‍ !

I want to have the whole page visible only to people who have „logged in“.
Logged in in quotes because I don’t want them to actually log in via the shopware login, since the data about the users is coming from the external service and is using completely different set of fields (there is no email, there is no user names, no addresses,…). What i’m using for login are 3 fields in a custom table and if user submits the „login form“ that info is looked up in the custom table and if match was found user is „logged in“ - I store their ID to the session and the fun can go on. If the „login“ data were wrong, I redirect back to login page with an error variable set.

For ANY request I just want to check in $_SESSION if that variable is present. If so, then it’s all good. If the variable is not present in session, then I want a redirect to the „login“ page.

So its like a fake, simplified login using a custom login controller. It works well with development mode turned on, but not in production.

If push comes to shove, I might just start digging starting in shopware.php file and finding the first place where I can access the $_SESSION variable and do this check there. But would love to have a better way, since editing shopware files makes the page unupdatable…

Any ideas that could move me to the right direction are welcome. thanks!

>I want to have the whole page visible only to people who have „logged in“.

Is it some custom controller or?

@odessite schrieb:

>I want to have the whole page visible only to people who have „logged in“.

Is it some custom controller or?

yes. The whole logic is in a class called FrontendSubscribere that i’ll attach below (at least the relavant parts)

class FrontendSubscriber implements SubscriberInterface
{
    public static function getSubscribedEvents() {
        return [
          'Enlight_Controller_Action_PreDispatch_Frontend' => 'onFrontendPreDispatch',
        ];
    }

    public function onFrontendPreDispatch(\Enlight_Event_EventArgs $arguments)
    {
        /** @var \Enlight_Controller_Action $controller */
        $controller = $arguments->get('subject');
        $controllerName = $controller->Request()->getControllerName();

        $passengerId = null;
        if(Shopware()->Session()) {
          $passengerId = Shopware()->Session()['passengerId'];
        }


        if(empty($passengerId) && $controllerName !== "passenger") {
            $controller->redirect('frontend/passenger/login');
        }
    }
}

So rather simple logic…

  • check if variable set in session
  • if it is not and the controller is not the custom controller that is responsible for „login“, do a redirect to the login page

all I need to do is execute this before the page is loaded from cache. (or maybe there is some other alternative that i’m not seeing at the moment)

>all I need to do is execute this before the page is loaded from cache

Any page of site?

If you can specify what exactly page/pages you want to hide - I can help you with solution.

Related this login to 3rd part service, should customer do this login all the time? Maybe if client logged in once you can store this info and show this/these pages in future without login?

All pages are available only after login. With the obvious exceptions of the login form itself and the action that processes the submitted data, that is what the code below does

if(empty($passengerId) && $controllerName !== "passenger") {
    $controller->redirect('frontend/passenger/login');
}

The customer should be logged in for the time of the session duration. If he/she comes back in a week he/she should log in again. trying to keep it as simple as possible.

thank you for your help

So you don’t use shopware login system at all?

In case customer logged in to shopware - he can’t do anything till log in to 3rd part service?

@odessite schrieb:

So you don’t use shopware login system at all?

In case customer logged in to shopware - he can’t do anything till log in to 3rd part service?

 shopware login system is still in place, so is registration and all that. At the moment the only way for the user can finish the checkout is by making a guest account, but that is besided the point here, that’s  another functionality.

the 3rd party service is delivering data that is imported to shopware and the „logging in“ actually takes place by a shopware controller that gets the 3 pieces of data the user submitted and just checks if an entry with this 3 pieces of data exists in a custom table in the shopware database (much like a normal login uses email and password, but the data we are using is from 3 parts).

until the user provides this data he can’t do anything (but look at the login form). from the moment he puts in the 3 pieces of data (and they are verified), he is a normal user of the shop, can use all the features and when the time comes for checkout, he needs to provide user information and addres and so on just like a normal guest on a normal shopware site would. Because those data is not included with the data we get from the 3rd party service…

imagine that you have a „private shop“ that only users that have been told certain secret words can access… and this session check needs to happen before the page is loaded from cache. If the site is in development mode it already works fine. All i need to do is move this check before the cache is checked…

In such case you should just rewrite shopware login to your custom.

So after user sign up to shopware - you should log out him, then user got login page and he can only do login with 3 pieces, which will check on 3rd service and in case such user exist - log in to shopware. Only thing - you should bind 3rd service data with shopware data, as case - customer should use same email like on 3rd part service, or you need to add additional field for registration, where customer should fill some uniq identifier from 3rd service.

This only right way which I see for your case, in other case you can use only development mode, but it isn’t right way for perfomance reasons.

i can’t do that, since the data we are using for login does not contain an email, so there is no way to connect the shopware login to the custom one. and I do need the user to go with the normal registration (where he/she provides the email and address), so we have the data we need to send the receipt and digital goods bought per email and the rest per post to his/her address.

@flynorc‍

Register should work via shopware like now, but after sign up - you shouldn’t sign in customer automatically.

Instead of this you should bind erp account with shopware account via  some uniq identifier and don’t use shopware auth. Instead of shopware sign in page - you should show your custom sign in page, after validate data with your 3rd part service - you fetch shopware user based on uniq identifier which bind service and shopware profile and do shopware login. In such behaviour customer don’t need to do two separate login and you can be sure each signed in customer valid with 3rd part service.

@odessite‍  i think you missunderstood the whole 3rd party signup. 3rd party is delivering batches of users that are beeing imported to a custom table in shopware database. So the login is just a matter of running a select query and checking if user with this credentials exists in a custom table in shopware database. This table however does not have any data that shopware customer needs (shipping address, email address, title, name ,…)

there is no need to contact the 3rd party service on login itself, because the data from it is beeing imported to the shopware database.
this all works already.

all what I want is to have the option to say something in the lines of this pseudo code

if ($_SESSION['passengerId'] === null && url !== "login") {
    redirect to login page
}

and this 3 lines of code should run somewhere where session is already available, but before page is loaded from cache

>and this 3 lines of code should run somewhere where session is already available, but before page is loaded from cache

It’s possible only in development mode.

>3rd party is delivering batches of users that are beeing imported to a custom table in shopware database. So the login is just a matter of running a select query and checking if user with this credentials exists in a custom table in shopware database. This table however does not have any data that shopware customer needs (shipping address, email address, title, name ,…)

User should do registration via shopware, but after registration you shouldn’t do authorization for this user. After customer register - you redirect him to your custom login page, where he sign in with 3rd service credentials, if customer in 3rd service exist - you should authorize this user via shopware.

Look:

  1. In case you need to do sign in with 3rd service only once - you should create additional group, when user sign up - he can only see sign in to 3rd service page, as soon as this customer sign in - you change group to EK. Then use only shopware auth.

  2. In case you need to check 3rd part service all the time - you should use 3rd service auth instead of default shopware auth. In this case you need to add to this 3rd part service uniq identifier to bind shopware userId with 3rd part service.

 

It’s possible only in development mode.

That is not great as the page will be in production mode :confused:

User should do registration via shopware, but after registration you shouldn’t do authorization for this user. After customer register - you redirect him to your custom login page, where he sign in with 3rd service credentials, if customer in 3rd service exist - you should authorize this user via shopware.

 User does not do any kind of registration. The user data is imported to a custom table and is part of shopwares database. So we are using table custom_users and checking if there is an entry that matches the 3 columns that were submitted with the „login“ request.

 

Everything is already working, I just need to move those 3 lines of code somewhere they will always be executed before page is loaded from cache. I’ll start digging in the shopware code today to find such a place and hope it exists.

 

Thank you for your time and energy spent trying to help me with this @odessite

>Everything is already working, I just need to move those 3 lines of code somewhere they will always be executed before page is loaded from cache. I’ll start digging in the shopware code today to find such a place and hope it exists.

You can’t find it, it contradicts the http-caching principle.

http://joxi.ru/ZrJY9azC9VJVOA

AppCache check is cache source existed on cache dir, in case yes - fetch cache and send to customer. In this case shopware code haven’t been executed at all.

>User does not do any kind of registration. The user data is imported to a custom table and is part of shopwares database. So we are using table custom_users and checking if there is an entry that matches the 3 columns that were submitted with the “login” request.

I’m not really understand why you need to do such login process more then once? If user once logged in into 3rd part service - you can be sure it is the same user, no?

I did end up making an ugly hack arround it in the end… by simply fetching the session data from the database (since we are using the db driver for sessions) and checking before the caching is invoked. I’m not booting up the whole shopware, just making a db connection and executing that one query, so the performance hit should not be too much of a problem.

 

The login is not handled by the 3rd party service. the 3rd party service just provides the user data in batches, once per week or so there are 1000-10000 potential new users and those are then imported (via cron job) into the custom users table (in shopware database), that is then used to check if user has the access to the site.

I need to look into how customer groups are working, because there must be different caches for different customer groups, but I don’t know how i can say

  • by default user is in customer group called „guest“ and therefore can only see the login page
  • after logging in user is in „user“ group and can browse page normaly.
    Where is this customer group information stored? How does shopware know which group a user belongs to when opening a page? What do I need to implement in the custom login function to assign an user to a group?

So for now it is working, but it’s for sure not pretty and not the right way to go about this, but it was driving me crazy already

>because there must be different caches for different customer groups

Right.

 

>- by default user is in customer group called “guest” and therefore can only see the login page
>- after logging in user is in “user” group and can browse page normaly.

It’s similar I propose you to do:

>1. In case you need to do sign in with 3rd service only once - you should create additional group, when user sign up - he can only see sign in to 3rd service page, as soon as this customer sign in - you change group to EK. Then use only shopware auth.

But I’m still don’t sure, customer account on 3rd service can be edited?

 

>Where is this customer group information stored?

I’m not sure what exactly do you mean:

You can create new group via backend - Configuration -> Basic Settings -> Shop Settings -> Customer groups

Data  stored in s_core_customergroups.

Users tables contain data about group in s_user.customergroup(there is key, not id).

Current customer groupkey you can find in

 Shopware()-\>Session()-\> **sUserGroup**

>How does shopware know which group a user belongs to when opening a page?

You can switch default(guest and customers) group there:

http://joxi.ru/4Akon7gtyWMlkA

 

>What do I need to implement in the custom login function to assign an user to a group?

I can’t provide stable solution for such case, you can edit session, but I don’t know how offten shopware will update session variable. You can edit customer group after sucessfull login, but then you should find a right way to revert usergroup back to guest…