Zitat:
OK, ich glaube, Jellys Lösung ist in meinem Fall ideal.
Ein kleines Problemchen habe ich aber noch: stellen wir vor, die Anwendung hat die Verbindung mit der
MSSQL-Datenbank, dann ändert Provider plötzlich die
IP-Adresse. Verbindung wird abgebrochen, Anwendung läuft jedoch weiter. In der sysprocesses wird der entsprechende Datensatz sofort gelöscht. Das heisst, anderer User kann sich schon problemlos einlogen. Und das alles kann öffters vorkommen, weil die Provider heutzutage ändern die
IP-Adressen ständig. Gibt es was dagegen?
In diesem Fall musst du
imho den "einfachen und sicheren Weg" verlassen und selbst was bauen.
Ich habe dir dazu mal schnell was ausgearbeitet.
Erstelle dir aber bitte eine eigene Datenbank, bitte keine Experimente mit der "Master-
DB"
Hier mal der grobe Ablauf:
1. Du brauchst eine
DB
> Enterprise Manager > Neue Datenbank > Name "LoginTest"
2. Du brauchst eine Tabelle in der Benutzer und Workstations gespeichert werden
SQL-Code:
USE LoginTest
GO
CREATE TABLE [SYS_ActiveUsers]
(
[USERNAME] varchar(50) NOT NULL, -- Spalte für den Benutzernamen
[Workstation] varchar(12) NOT NULL, -- Spalte für den Netbiosnamen der Workstarion
[LAST_SEEN] datetime DEFAULT (getdate()) NOT NULL, -- Spalte für das letzte Login/KeepAlive eines Users
[LOCK_TIME_SECS] int DEFAULT (600) NOT NULL -- (bedingte) Verfallszeit in Sekunden
)
ON [PRIMARY]
GO
3. Du brauchst eine SP, die beim Anmelden jedes einzelnen Users aufgerufen wird.
Dieser SP übergibst du den aktuellen Benutzernamen und den aktuellen PC-Namen.
Sie gibt dir ein BIT (AllowLogin) zurück, das du in deiner Software auswerten kannst.
Zudem gibt es ein BIT (Logout) mit dem du einen User regulär ausloggen kannst.
SQL-Code:
Use LoginTest
GO
CREATE PROCEDURE SYS_Check_Single_Login
(
@USERNAME
VARCHAR(50) =
NULL,
@WORKSTATION
VARCHAR(12) =
NULL,
@LOGOUT
BIT =
NULL,
@AllowLogin
BIT = 0 OUTPUT
)
AS
BEGIN
-- Variablen deklarieren
DECLARE @TEMPTIME
DATETIME
DECLARE @TEMPDIFF
INTEGER
-- Parameter überprüfen
IF @USERNAME
IS NULL OR @WORKSTATION
IS NULL
BEGIN
SET @AllowLogin = 0
RAISERROR('
Benutzername und Arbeitsstationsname müssen übermittelt werden',16,1,'
SQL-Login')
END
-- Logout ??
IF @LOGOUT
IS NULL SET @LOGOUT =0
IF @LOGOUT = 1
BEGIN
-- Benutzer meldet sich regulär ab
DELETE FROM SYS_ActiveUsers
WHERE USERNAME=@USERNAME
AND WORKSTATION=@WORKSTATION
-- ggf. weglassen, damit das ganze Geraffel nicht zu starr wird ..
SET @AllowLogin=0
END
ELSE BEGIN
IF EXISTS (
SELECT USERNAME
FROM SYS_ActiveUsers
WHERE USERNAME=@USERNAME
AND WORKSTATION = @WORKSTATION
)
BEGIN
-- Relogin (selber User von der selben Workstation)
-- Last_Seen Updaten und AllowLogin setzen
UPDATE SYS_ActiveUsers
SET LAST_SEEN = GETDATE()
WHERE USERNAME=@USERNAME
SET @AllowLogin=1
END
ELSE BEGIN
IF EXISTS (
SELECT USERNAME
FROM SYS_ActiveUsers
WHERE USERNAME=@USERNAME
AND WORKSTATION <> @WORKSTATION
)
BEGIN
-- Login des selben Users von einer anderen Workstation)
-- "Verfallsdatum" prüfen, ggf. Last_Seen Updaten und AllowLogin setzen
SELECT @TEMPTIME = LAST_SEEN,
@TEMPDIFF = LOCK_TIME_SECS
FROM SYS_ActiveUsers
WHERE USERNAME=@USERNAME
AND WORKSTATION <> @WORKSTATION
IF ABS( DATEDIFF( SECOND,@TEMPTIME,GETDATE() ) ) > @TEMPDIFF
BEGIN
-- Das "Verfallsdatum" des letzten Logins ist abgelaufen
-- Tabelle SYS_ActiveLogins um den verwaisten User bereinigen
DELETE FROM SYS_ActiveUsers
WHERE USERNAME=@USERNAME
-- Eigenen USERNAME und Workstation in SYS_ActiveUsers eintragen
INSERT INTO SYS_ActiveUsers (USERNAME
,WORKSTATION
,LAST_SEEN
,LOCK_TIME_SECS)
VALUES (@USERNAME
,@WORKSTATION
,GETDATE()
,600)
-- Timeout Sekunden (Verfallszeit)
SET @AllowLogin=1
END
ELSE BEGIN
-- Das "Verfallsdatum" des letzten Logins ist nicht nicht überschritten
-- Login verweigern
SET @AllowLogin=0
END
END
ELSE BEGIN
-- USERNAME steht noch nicht in der Tabelle SYS_ActiveUsers
-- Hinzufügen ...
INSERT INTO SYS_ActiveUsers (USERNAME
,WORKSTATION
,LAST_SEEN
,LOCK_TIME_SECS)
VALUES (@USERNAME
,@WORKSTATION
,GETDATE()
,600)
-- Timeout Sekunden (Verfallszeit)
SET @AllowLogin=1
END
END
END
END
Diese SP rufst du beim Annmelden eines Users auf, und sie gibt dir, wie gesagt, ein Bit zurück, mit dem du prüfen kannst, ob sich der User anmelden darf.
Zum Ausloggen ruft du die selbe SP noch einmal auf, jedoch mit dem Parameter Logout = 1
Um das KeepAlive eines Users zu setzen, ruft du die SP alle 5-8 Minuten mal wieder auf ...
Für die Delphi würde ich mir an deiner Stelle eine kleine Function basteln:
Delphi-Quellcode:
var
isAuthentificated:Boolean;
function CheckLogin(Logout:Boolean): Boolean;
var SP:TAdoStoredProc;
begin
{
SQL - Syntax Hinweis
--------------------------------------------
CREATE PROCEDURE SYS_Check_Single_Login
(
@USERNAME VARCHAR(50) = NULL,
@WORKSTATION VARCHAR(12) = NULL,
@LOGOUT BIT = NULL,
@AllowLogin BIT = 0 OUTPUT
)
}
SP:=TAdoStoredProc.create(self);
SP.Connection:=MeineAdoConn;
// Hier deine AdoConn
try
SP.Procedurename:='
SYS_Check_Single_Login';
SP.Parameters.refresh;
SP.Parameters[1].Value:=MeinUserName;
SP.Parameters[2].Value:=MeinPcName;
if Logout
then SP.Parameters[3].Value:=1
else SP.Parameters[3].Value:=0;
SP.ExecProc;
Result:=SP.Parameters[4].Value;
finally
FreeAndNil(SP);
end;
if Authentificated
AND (
NOT Logout)
AND (
NOT Result)
then
begin
Showmessage('
Ihr login wirde gelöscht, weil von Ihrer Arbeitsstation keine "KeepAlive-Aufrufe"'+#13#10+
'
an die SP "SYS_Check_Single_Login" gesendet wurden, bzw. deren Timing nicht passt ...');
end;
if (
NOT Authentificated)
AND (
NOT Result)
then
begin
Showmessage('
Ein anderer Benutzer ist im Moment als "'+MeinUsername+'
" angemeldet.'+#13#10+
'
Bitte verwenden Sie einen anderen Benutzernamen oder versuchen Sie es später noch einmal.');
end;
isAuthentificated:=(
NOT Logout)
AND RESULT;
end;
Hoffentlich ist das eine Lösung, die deinen Anforderungen annähernd entspricht ...
Schöne Grüße,
Jens
(bearbeitet - ein paar Kleinigkeiten korrigiert ...)