Dans une application Web implémentée dans Java à l'aide de JSP et de Servlets; Si je stocke des informations dans la session utilisateur, ces informations sont partagées à partir de tous les onglets du même navigateur. Comment différencier les sessions dans les onglets du navigateur? Dans cet exemple:
<%@page language="Java"%>
<%
String user = request.getParameter("user");
user = (user == null ? (String)session.getAttribute("SESSIONS_USER") : user);
session.setAttribute("SESSIONS_USER",user);
%>
<html><head></head><body>
<%=user %>
<form method="post">
User:<input name="user" value="">
<input type="submit" value="send">
</form>
</body></html>
Copiez ce code dans une page jsp (testpage.jsp
), déployez ce fichier dans le contexte existant d’une application Web sur le serveur (j’utilise Apache Tomcat), puis ouvrez un navigateur (FF, IE7 ou Opera) en utilisant le fichier correct. URL (localhost/context1/testpage.jsp
), saisissez votre nom et saisissez le formulaire. Ouvrez ensuite un nouvel onglet dans le même navigateur et vous pourrez voir votre nom (extrait de la session) sur le nouvel onglet. Faites attention avec le cache du navigateur, cela semble parfois ne pas se produire, mais c'est dans le cache, actualisez le deuxième onglet.
Merci.
Vous pouvez utiliser HTML5 SessionStorage (window.sessionStorage). Vous allez générer un identifiant aléatoire et enregistrer dans la session Stockage par onglet du navigateur. Ensuite, chaque onglet du navigateur a son propre identifiant.
Les données stockées à l'aide de sessionStorage ne persistent pas dans les onglets du navigateur, même si deux onglets contiennent des pages Web du même domaine Origine. En d'autres termes, les données à l'intérieur de sessionStorage ne se limitent pas au domaine et au répertoire de la page appelante, mais également à l'onglet du navigateur dans lequel la page est contenue. Contrastez cela aux cookies de session, qui conservent les données d'un onglet à l'autre.
Vous devez comprendre que les sessions côté serveur sont un complément artificiel à HTTP. Étant donné que HTTP est sans état, le serveur doit reconnaître en quelque sorte qu'une demande appartient à un utilisateur particulier pour lequel il dispose d'une session. Il y a 2 façons de faire cela:
Qu'essayez-vous de faire de toute façon? Pourquoi voudriez-vous que les onglets aient des sessions séparées? Peut-être qu’il ya un moyen d’atteindre votre objectif sans utiliser de sessions du tout?
Edit: Pour le test, d'autres solutions peuvent être trouvées (telles que l'exécution de plusieurs instances de navigateur sur des ordinateurs virtuels distincts). Si un utilisateur doit agir simultanément dans différents rôles, le concept de "rôle" doit être géré dans l'application de sorte qu'un identifiant de connexion puisse avoir plusieurs rôles. Vous devrez décider si ceci, en utilisant la réécriture d'URL, ou simplement vivre avec la situation actuelle est plus acceptable, car il est tout simplement impossible de gérer les onglets du navigateur séparément avec des sessions basées sur des cookies.
Vous ne devriez pas. Si vous voulez faire cela, vous devez obliger l'utilisateur à utiliser une seule instance de votre application en écrivant des URL à la volée et en utilisant un identifiant sessionID identique (pas sessionid, il l'a gagné). t work) id et le transmettre dans chaque URL.
Je ne sais pas pourquoi vous en avez besoin, mais à moins que vous n'ayez besoin de faire une application totalement inutilisable, ne le faites pas.
La propriété Javascript window.name est la seule chose qui persiste dans l’activité des onglets, mais qui peut rester indépendante (au lieu de guff d’URL).
Je suis venu avec une nouvelle solution, qui a un peu de frais généraux, mais semble fonctionner jusqu'à présent comme un prototype. Une hypothèse est que vous vous connectez dans un environnement système d'honneur, bien que cela puisse être adapté en recherchant un mot de passe à chaque changement d'onglet.
Utilisez localStorage (ou l’équivalent) et l’événement de stockage HTML5 pour détecter quand un nouvel onglet de navigateur a basculé quel utilisateur est actif. Lorsque cela se produit, créez une superposition fantôme avec un message indiquant que vous ne pouvez pas utiliser la fenêtre en cours (ou désactivez temporairement la fenêtre, vous voudrez peut-être que ce ne soit pas aussi visible.) Lorsque la fenêtre reprend le focus, envoyez un AJAX request reconnexion de l'utilisateur.
Une mise en garde à cette approche: vous ne pouvez pas avoir d'appels normaux AJAX (c.-à-d. Ceux qui dépendent de votre session) se déroulent dans une fenêtre qui n'a pas le focus (par exemple, si vous avez un appel passé après un délai), à moins que vous ne fassiez manuellement un appel AJAX avant de vous reconnecter. Donc, tout ce dont vous avez besoin est de faire vérifier votre fonction AJAX pour vous assurer que localStorage.currently_logged_in_user_id === window.yourAppNameSpace.user_id et sinon, connectez-vous d'abord via AJAX.
Les conditions de concurrence en sont un autre exemple: si vous pouvez changer de fenêtre assez rapidement pour la rendre confuse, vous risquez de vous retrouver avec une séquence relogin1-> relogin2-> ajax1-> ajax2, avec ajax1 créé sous la mauvaise session. Contournez ce problème en transférant les demandes de login AJAX sur un tableau, puis annulez toutes les requêtes en cours avant de lancer une nouvelle demande de connexion.
La dernière chose à surveiller est le rafraîchissement de la fenêtre. Si quelqu'un actualise la fenêtre alors que vous avez une demande de connexion AJAX active mais non terminée, le nom de la mauvaise personne sera actualisé. Dans ce cas, vous pouvez utiliser l'événement beforeunload non standard pour avertir l'utilisateur du risque de confusion et lui demander de cliquer sur Annuler tout en émettant de nouveau une demande de connexion AJAX. Ensuite, le seul moyen de le faire est de cliquer sur OK avant la fin de la demande (ou de frapper accidentellement sur entrée/barre d'espace, car OK est - malheureusement pour ce cas-ci, la valeur par défaut.) Il existe d'autres moyens de gérer ce cas, comme détecter les pressions F5 et Ctrl + R/Alt + R, ce qui fonctionnera dans la plupart des cas mais pourrait être contrecarré par la reconfiguration des raccourcis clavier de l'utilisateur ou l'utilisation d'un autre système d'exploitation. Cependant, c’est un peu un cas d’Edge en réalité, et les pires scénarios ne sont jamais aussi graves: dans une configuration de système honoraire, vous seriez connecté en tant que mauvaise personne (mais vous pouvez faire comprendre que c’est la cas en personnalisant les pages avec des couleurs, des styles, des noms bien en évidence, etc.); dans une configuration de mot de passe, il incombe à la dernière personne qui a entré son mot de passe de se déconnecter ou de partager sa session ou, si cette personne est en fait l'utilisateur actuel, il n'y a pas d'infraction.
Mais au final, vous avez une application avec un utilisateur par onglet qui (espérons-le) agit comme il se doit, sans avoir à configurer des profils, à utiliser IE ou à réécrire des URL. Assurez-vous d'indiquer clairement dans chaque onglet qui est connecté à cet onglet en particulier ...
Nous avons eu ce problème et nous l'avons résolu très facilement. Je veux dire facile parce qu'aucune programmation n'est impliquée. Ce que nous voulions faire était de laisser un utilisateur se connecter à plusieurs comptes dans la même fenêtre de navigateur sans créer de conflit entre les sessions.
La solution était donc des sous-domaines aléatoires.
23423.abc.com
242234.abc.com
235643.abc.com
Nous avons donc demandé à notre administrateur système de configurer les certificats SSL pour * .abc.com plutôt que abc.com. Alors avec peu de changement de code, chaque fois qu'un utilisateur essaie de se connecter, il est connecté dans un onglet avec un numéro de sous-domaine aléatoire. afin que chaque onglet puisse avoir sa propre session indépendamment. Aussi, pour éviter tout conflit, nous avons développé le nombre aléatoire en utilisant un hash ou md5 d’identifiant utilisateur.
Je serai honnête ici. . .tout ci-dessus peut être ou ne pas être vrai, mais tout semble MANIÈRE trop compliqué, ou ne répond pas en sachant quel onglet est utilisé côté serveur.
Parfois, nous devons appliquer le rasoir d'Occam.
Voici l'approche d'Occam: (non, je ne suis pas Occam, il est mort en 1347)
1) attribuer un identifiant unique du navigateur à votre page lors du chargement. . . si et seulement si la fenêtre n'a pas encore d'identifiant (utilisez donc un préfixe et une détection)
2) sur chaque page que vous avez (utilisez un fichier global ou quelque chose de ce genre), mettez simplement du code en place pour détecter l’événement de focus et/ou le survol de la souris. (J'utiliserai jquery pour cette partie, pour faciliter l'écriture de code)
3) dans votre fonction focus (et/ou mouseover), définissez un cookie contenant le nom window.name
4) lisez cette valeur de cookie côté serveur lorsque vous devez lire/écrire des données spécifiques à un onglet.
Côté client:
//Events
$(window).ready(function() {generateWindowID()});
$(window).focus(function() {setAppId()});
$(window).mouseover(function() {setAppId()});
function generateWindowID()
{
//first see if the name is already set, if not, set it.
if (se_appframe().name.indexOf("SEAppId") == -1){
"window.name = 'SEAppId' + (new Date()).getTime()
}
setAppId()
}
function setAppId()
{
//generate the cookie
strCookie = 'seAppId=' + se_appframe().name + ';';
strCookie += ' path=/';
if (window.location.protocol.toLowerCase() == 'https:'){
strCookie += ' secure;';
}
document.cookie = strCookie;
}
côté serveur (C # - à titre d'exemple)
//variable name
string varname = "";
HttpCookie aCookie = Request.Cookies["seAppId"];
if(aCookie != null) {
varname = Request.Cookies["seAppId"].Value + "_";
}
varname += "_mySessionVariable";
//write session data
Session[varname] = "ABC123";
//readsession data
String myVariable = Session[varname];
Terminé.
Utilisez essentiellement window.name. S'il n'est pas défini, définissez-le sur une valeur unique et utilisez-le. Ce sera différent selon les onglets appartenant à la même session.
Je pense que ce que vous voulez probablement est de maintenir l’état de navigation entre les onglets et non de créer spécifiquement une seule session par onglet. C’est exactement ce que le framework Seam réalise avec son périmètre/contexte de conversation. Leur implémentation repose sur le fait qu’un identifiant de conversation est propagé à chaque requête et crée la notion de conversation côté serveur, qui se situe entre une session et une requête. Il permet le contrôle du flux de navigation et la gestion des états.
Bien qu’il s’agisse principalement de JSF, jetez un œil et vérifiez si vous pouvez en tirer quelques idées: http://docs.jboss.org/seam/latest/reference/en-US/html_single/# d0e362
Une autre approche qui fonctionne consiste à créer un identifiant de fenêtre unique et à stocker cette valeur avec l'identifiant de session dans une table de base de données. L'identifiant de la fenêtre que j'utilise souvent est un entier (maintenant). Cette valeur est créée à l'ouverture d'une fenêtre et réaffectée à la même fenêtre si celle-ci est actualisée, rechargée ou soumise à elle-même. Les valeurs de fenêtre (entrées) sont enregistrées dans la table locale à l'aide du lien. Lorsqu'une valeur est requise, elle est obtenue à partir de la table de base de données en fonction du lien id Windows/ID de session. Bien que cette approche nécessite une base de données locale, elle est pratiquement infaillible. L'utilisation d'une table de base de données était facile pour moi, mais je ne vois aucune raison pour que les tableaux locaux ne fonctionnent pas aussi bien.
Vous pouvez utiliser la réécriture de liens pour ajouter un identifiant unique à toutes vos URL lorsque vous démarrez sur une seule page (par exemple, index.html/jsp/what). Le navigateur utilisera les mêmes cookies pour tous vos onglets, de sorte que tout ce que vous insérerez dans les cookies sera non unique.
La session de printemps prend en charge plusieurs sessions dans le même navigateur Consultez les exemples et les détails de la mise en œuvre http://docs.spring.io/spring-session/docs/current/reference/html5/guides/users.html
J'ai récemment développé une solution à ce problème en utilisant des cookies. Voici un lien vers ma solution. J'ai également inclus un exemple de code de la solution utilisant ASP.NET. Vous devriez pouvoir l'adapter à JSP ou à Servelets si vous en avez besoin.
https://sites.google.com/site/sarittechworld/track-client-windows
Je vois de nombreuses implémentations qui ont des modifications côté client pour manipuler les cookies d'identification de session. Mais en général, les cookies d'identification de session doivent être HttpOnly pour que le script Java ne puisse pas accéder, sans quoi cela pourrait conduire à un détournement de session via XSS.
Si c'est parce que chaque onglet exécute un flux différent dans votre application et que le mélange des deux flux pose des problèmes, il est préférable de "Régionaliser" vos objets de session afin que chaque flux utilise une région différente de la session.
Cette région peut être implémentée simplement en ayant différents préfixes pour chaque flux, ou un objet de session contiendra plusieurs mappes (une pour chaque flux), et vous utiliserez ces mappes au lieu d'attributs de session. Le mieux serait d'étendre votre classe de session. utilisez-le à la place.
Stocker timeStamp dans window.sessionStorage s'il n'est pas déjà défini. Cela donnera une valeur unique pour chaque onglet (même si les URL sont identiques)
http://www.javascriptkit.com/javatutors/domstorage.shtml
https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage
J'espère que cela t'aides.
vous devrez faire
1- stocker un cookie pour la liste des comptes
2- en option stocker un cookie pour celui par défaut
3- stocker pour chaque compte avec son index comme acc1, acc2
4- mettez dans l'url quelque chose représente l'index des comptes et sinon vous sélectionnerez celui par défaut comme google mail domain.com/0/some-url >> 0 représente l'index du compte et vous devrez peut-être savoir comment utiliser urlwrite
5- Lorsque vous sélectionnez un cookie, sélectionnez-le en fonction de votre chemin url, qui représente l'index du compte.
Cordialement
Remarque: La solution ici doit être faite au stade de la conception de l'application. Il serait difficile de concevoir cela plus tard.
Utilisez un champ masqué pour transmettre l'identifiant de session .
Pour que cela fonctionne, chaque page doit inclure un formulaire:
<form method="post" action="/handler">
<input type="hidden" name="sessionId" value="123456890123456890ABCDEF01" />
<input type="hidden" name="action" value="" />
</form>
Chaque action de votre côté, y compris la navigation, renvoie le formulaire (en définissant la action
comme il convient). Pour les demandes "non sécurisées" , vous pouvez inclure un autre paramètre, par exemple contenant une valeur JSON des données à soumettre:
<input type="hidden" name="action" value="completeCheckout" />
<input type="hidden" name="data" value='{ "cardNumber" : "4111111111111111", ... ' />
Comme il n'y a pas de cookies, chaque onglet sera indépendant et n'aura aucune connaissance des autres sessions du même navigateur.
De nombreux avantages, notamment en matière de sécurité:
Quelques inconvénients:
J'ai lu ce post parce que je pensais que je voulais faire la même chose. J'ai une situation similaire pour une application sur laquelle je travaille. Et, en réalité, il s’agit de tester plus que de la praticité.
Après avoir lu ces réponses, en particulier celle de Michael Borgwardt, j'ai réalisé le flux de travail qui doit exister:
Cela résoudra le problème de voir les données d'un "autre utilisateur" dans leur session. Ils ne voient pas vraiment les données d'un "autre utilisateur" dans leur session, ils voient vraiment les données de la seule session ouverte. Clairement, cela cause certaines données intéressantes, car certaines opérations écrasent certaines données de session et pas d'autres, de sorte que vous disposez d'une combinaison de données dans cette session.
Maintenant, pour aborder la question des tests. La seule approche viable consisterait à utiliser directives du préprocesseur pour déterminer si des sessions sans cookies doivent être utilisées. Vous voyez, en construisant une configuration spécifique pour un environnement spécifique, je suis en mesure de formuler des hypothèses sur l'environnement et sur son utilisation. Cela me permettrait techniquement d'avoir deux utilisateurs connectés en même temps et que le testeur puisse tester plusieurs scénarios à partir de la même session de navigateur sans jamais se déconnecter d'aucune de ces sessions de serveur.
Cependant, cette approche présente de sérieuses mises en garde. Notamment, le testeur teste et non ce qui sera exécuté en production.
Je pense donc que je dois dire que c’est finalement une mauvaise idée .
J'ai résolu ceci de manière suivante:
voici le code:
var deferred = $q.defer(),
self = this,
onConnect = function(status){
if (status === Strophe.Status.CONNECTING) {
deferred.notify({status: 'connecting'});
} else if (status === Strophe.Status.CONNFAIL) {
self.connected = false;
deferred.notify({status: 'fail'});
} else if (status === Strophe.Status.DISCONNECTING) {
deferred.notify({status: 'disconnecting'});
} else if (status === Strophe.Status.DISCONNECTED) {
self.connected = false;
deferred.notify({status: 'disconnected'});
} else if (status === Strophe.Status.CONNECTED) {
self.connection.send($pres().tree());
self.connected = true;
deferred.resolve({status: 'connected'});
} else if (status === Strophe.Status.ATTACHED) {
deferred.resolve({status: 'attached'});
self.connected = true;
}
},
output = function(data){
if (self.connected){
var rid = $(data).attr('rid'),
sid = $(data).attr('sid'),
storage = {};
if (localStorageService.cookie.get('day_bind')){
storage = localStorageService.cookie.get('day_bind');
}else{
storage = {};
}
storage[$window.name] = sid + '-' + rid;
localStorageService.cookie.set('day_bind', angular.toJson(storage));
}
};
if ($window.name){
var storage = localStorageService.cookie.get('day_bind'),
value = storage[$window.name].split('-')
sid = value[0],
rid = value[1];
self.connection = new Strophe.Connection(BoshService);
self.connection.xmlOutput = output;
self.connection.attach('bosh@' + BoshDomain + '/' + $window.name, sid, parseInt(rid, 10) + 1, onConnect);
}else{
$window.name = 'web_' + (new Date()).getTime();
self.connection = new Strophe.Connection(BoshService);
self.connection.xmlOutput = output;
self.connection.connect('bosh@' + BoshDomain + '/' + $window.name, '123456', onConnect);
}
J'espère t'aider
How to differ sessions in browser-tabs?
Le moyen le plus simple de différer les sessions dans les onglets du navigateur est d'interdire à votre domaine particulier de définir des cookies. De cette façon, vous pouvez avoir des sessions séparées à partir d'onglets séparés. Supprimez les cookies de ce domaine: www.xyz.com. Vous ouvrez l'onglet 1, connectez-vous et commencez à naviguer. Ensuite, vous ouvrez l'onglet 2 et vous pouvez vous connecter en tant que même utilisateur ou différent; de toute façon, vous aurez une session séparée de l’onglet 1. Et ainsi de suite.
Mais bien sûr, cela est possible lorsque vous avez le contrôle du côté client. Sinon, les solutions prescrites par les gens ici devraient s'appliquer.