10

I am running Opencart v2.3.0.2 multi store on several domains (not sub-domains) and want to Checkout on main site, which has all the products from all the stores.

Since it is hard to share sessions on multiple domains, think it is best to force user login before the Checkout process (login credentials are same for all stores and Cart items are shared). But, by default, users have to login into each store separately - how can I create single login into/for all stores? Once logged in, I can send them to main site to checkout.

If you think there is a better way for single checkout, please suggest.

skobaljic
  • 9,379
  • 1
  • 25
  • 51
  • 1
    This might be helpful: http://stackoverflow.com/questions/5062569/how-to-do-single-sign-on-with-php – Derenir Feb 17 '17 at 15:04
  • I've read maybe 50 articles and best of them are similar to above. In one I found, guy recommends two redirects in between slave/master site and there set same token. I really hope there is some better way with Opencart, considering all shops are maintained with one script. Maybe setting a hidden iframe, or posting from slave to master site is better solution. Maybe the link itself, pointing to master site Checkout should hold the token... reward for best solution! – skobaljic Feb 17 '17 at 15:54
  • are u using - multiple servers with multiple Databases or - one Server with multiple Databases like this : `(1nd database) serve_1.com --> site_1.com ,,,,,, (2nd database) server_1.com --> site_2.com .` – The Doctor Feb 19 '17 at 18:53
  • I am using one server, one Opencart instance, with several addon domains. – skobaljic Feb 20 '17 at 01:15
  • Main site has all the products, secondary sites may have manufacturer's stuff, so main can be electronics.com, secondary samsungtv.com, or samsungcameras.com. Look at my comment below, setting those 2 cookies with same values on all sites solves the problem, the question is when/where to set them. Those should be session http only cookies and should be set only once. – skobaljic Feb 20 '17 at 01:23
  • @skobaljic can't feel 100% secure about sending login links with cookies to all domains cause it need much security to avoid the manipulate and some hackers are good in that,he can use redi-links from other machine. ,, u can try : if its one server + multi databases lets say : `server1={Db1 + Db2 + Db3 }` then basically we can call all Databases in one `Addons script` , and name it for example : `( Ch-Addons.php )` , and coding inside it to check if the user are login or not in all databases . , then we close the script with `$db1->close(); $db2->close(); .... etc` when the checkout is end . – The Doctor Feb 20 '17 at 10:48
  • Have a look at this approach ,it in java but would help you https://secure.identity.ucsb.edu/inside/doku.php/sso_java – gladiator Feb 24 '17 at 08:41

3 Answers3

3

If its enough for you to simply login your user in all stores (and you don't wont to use same session id) you can

1) implemented login link locking for all your stores

2) after successful login to one of your stores in response send him back all rest stores login links

3) execute each login link by ajax.

so as result you will login to one fore but automatically login to all stores

NOTE: best will be if your login form itself will be also by ajax so user will simply enter credentials and in case of success see longer ajax load during which you will one by one execute rest login links

Armen
  • 4,064
  • 2
  • 23
  • 40
  • I see Opencart sets two cookies **PHPSESSID** and **default**. If I manually copy those values to other site, than I have same items in Cart and I'm logged in in both websites (in case I'm logged in). Maybe posting and setting those cookies via AJAX, or via PHP somehow is better. Just warring about security, 'cause main site use SSL and others don't (at this time). – skobaljic Feb 18 '17 at 11:04
  • You can through ajax post nececary info to some php script which will do things for you. Also though https ajax request. – Armen Feb 18 '17 at 12:54
  • I will go and set those two cookies with same values to all of my stores, that's all the Opencart needs to know. There is no need to send login info, once the cookies are identical, customer is unique on all the sites. I will use old JS method to load an 1px png image on other sites, that worked many times. – skobaljic Feb 24 '17 at 02:04
2

What you want is Single Sign On. There are many ways to do that, one more secure way is to use JSON Web Token (like https://github.com/lcobucci/jwt). In short, these are signed JSON strings so you use the power of asynchronous encryption! ;)

Salic
  • 49
  • 5
  • I will just sync the session cookies over sites. Not sure if I need this library, think I can do it with simple ajax requesting an image, than do cookies sync. Thanks for sharing the link and help. – skobaljic Feb 24 '17 at 02:10
0

Opencart 2 sets two HTTPOnly cookies PHPSESSID and default to identify the customer. Therefore, I decided to share/sync them over the stores.

1. Get the list of stores for Javascript

Maybe not best, but in /catalog/controller/common/header.php I assigned a variable:

$this->load->language('setting/store');
$this->load->model('setting/store');
$this->load->model('setting/setting');

$data['multi_stores'] = array();

$data['multi_stores'][] = array(
    'store_id'      => 0,
    'name'          => 'Main Site',
    'url'           => 'https://mysite.co.uk/',
    'is_current'    => stripos('https://mysite.co.uk/', $_SERVER['SERVER_NAME']) !== false
);

$results = $this->model_setting_store->getStores();
foreach ($results as $result) {
    $data['multi_stores'][] = array(
        'store_id'      => $result['store_id'],
        'name'          => $result['name'],
        'url'           => $result['url'],
        'is_current'    => stripos($result['url'], $_SERVER['SERVER_NAME']) !== false
    );
}

2. Than in template I used it:

<script type="text/javascript">
var multiStores = <?php echo json_encode($multi_stores); ?>;
</script>

3. Created two PHP scripts to set and get cookies:

  • Please note, to set PHP HTTPOnly cookie, the 7th parameter must be true.
  • Another note, to get HTTPOnly cookie we have to request it from server, it is not accessible via Javascript (which is its purpose in first place).

getCookies.php:

$cookies = array(
    'PHPSESSID' => $_COOKIE['PHPSESSID'],
    'default' => $_COOKIE['default'],
    'currency' => $_COOKIE['currency'],
    'language' => $_COOKIE['language']
);

header('Content-Type: application/json');
echo json_encode( $cookies );

setCookies.php:

$response = array(
    'status' => 'ok'
);

/* Format: [cookie name] => [expire days] */
$cookies_to_sync = array(
    'PHPSESSID' => '',
    'default' => '',
    'currency' => 30,
    'language'=> 30
);

/* If no expire was set, than set session HTTPOnly cookie (last, 7th parameter 'true') */
foreach( $cookies_to_sync as $cname=>$cexpire ) {
    if( $_POST[$cname] ) {
        if( $cexpire ) {
            /* 86400 seconds per day */
            setcookie($cname, $_POST[$cname], time() + (86400 * $cexpire), '/', null, null, false);
        } else {
            setcookie($cname, $_POST[$cname], null, '/', null, null, true);
        };
    };
};

/* Browser requests a JSON, cross-origin enabled, with OPTIONS enabled to set cookies */
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Max-Age: 1000');
header('Content-Type: application/json');
echo json_encode( $response );

4. The Javascript part: - Please note, in order to send/set cookies cross-domain, we set OPTIONS in PHP header and for jQuery we add $.ajax xhrFields option withCredentials: true. Having that in mind, I created my method to sync website cookies:

this.syncWebsites = function() {
    if( typeof multiStores!='undefined' ) {
        that.stores = multiStores;
        that.synced = that.readCookie('synced');
        if( !that.synced ) {
            /* First get cookies */
            $.getJSON( "catalog/view/theme/mytheme/javascript/getCookies.php", function( data ) {
                /* Send to other sites */
                $.each(that.stores, function(i, store) {
                    if( !store.is_current ) {
                        /* Send to other sites, MUST use xhrFields->withCredentials: true, to set cookies */
                        $.ajax({
                            url: store.url.replace('http://', '//') + "catalog/view/theme/mytheme/javascript/setCookies.php",
                            xhrFields: {
                                withCredentials: true
                            },
                            type: "post",
                            crossDomain: true,
                            data: data,
                            dataType: "json",
                            success:function(result){
                                that.echo(JSON.stringify(result));
                            },
                            error:function(xhr, status, error){
                                that.echo(status);
                            }
                        });
                    };
                });
                that.createCookie('synced', 'Yes', '');
            });
        };
    };
};

Please note: I created the synced cookie, so this requests happen only once during the session.

Final result: We have all the Opencart 2 customers synced on all websites.

Security considerations: All websites are using SSL encription. The danger of stealing the info is same as one would visit all of those websites.

skobaljic
  • 9,379
  • 1
  • 25
  • 51