Pertanyaan Ketika ID pengguna yang sama mencoba masuk di beberapa perangkat, bagaimana cara saya mematikan sesi di perangkat lain?


Yang ingin saya lakukan adalah membatasi ID pengguna untuk hanya bisa masuk ke satu perangkat dalam satu waktu. Misalnya, ID pengguna "abc" masuk ke komputer mereka. ID Pengguna "abc" sekarang mencoba masuk dari ponsel mereka. Yang ingin saya lakukan adalah membunuh sesi di komputer mereka.

Aplikasi Spotify melakukan persis ini- Spotify hanya memungkinkan satu User ID untuk masuk pada satu perangkat dalam satu waktu.

Saya menggunakan keanggotaan ASP.NET (SqlMembershipProvider) dan Otentikasi Formulir.

Saya sudah bereksperimen dengan variabel sesi tetapi saya tidak tahu pasti kemana harus pergi dari sini.


32
2018-04-09 13:40


asal


Jawaban:


Saya datang dengan solusi yang sangat luar biasa untuk ini. Apa yang telah saya terapkan adalah ketika pengguna "Bob" log in dari PC mereka, dan kemudian pengguna yang sama "Bob" masuk dari lokasi lain, log-in dari lokasi pertama (PC mereka) akan terbunuh sementara memungkinkan kedua log-in untuk hidup. Setelah pengguna masuk, ia memasukkan catatan ke tabel khusus yang saya buat bernama "Login". Setelah berhasil masuk, satu catatan akan dimasukkan ke dalam tabel ini dengan nilai untuk "UserId, SessionId, dan LoggedIn". UserId cukup jelas, SessionId adalah ID Sesi saat ini (dijelaskan di bawah ini bagaimana cara mendapatkannya), dan LoggedIn hanyalah sebuah Boolean yang pada awalnya diatur ke True pada saat pengguna login yang sukses. Saya menempatkan logika "sisipkan" ini di dalam metode Login dari AccountController saya setelah validasi yang berhasil dari pengguna- lihat di bawah ini:

Logins login = new Logins();
login.UserId = model.UserName;
login.SessionId = System.Web.HttpContext.Current.Session.SessionID;;
login.LoggedIn = true;

LoginsRepository repo = new LoginsRepository();
repo.InsertOrUpdate(login);
repo.Save();

Untuk situasi saya, saya ingin menempatkan cek pada masing-masing pengontrol saya untuk melihat apakah pengguna yang saat ini login login di tempat lain, dan jika demikian, bunuh sesi lain. Kemudian, ketika sesi yang terbunuh mencoba menavigasi di mana pun saya menempatkan pemeriksaan ini, itu akan mencatatnya dan mengalihkannya ke layar Log-in.

Saya memiliki tiga metode utama yang melakukan pemeriksaan ini:

IsYourLoginStillTrue(UserId, SessionId);
IsUserLoggedOnElsewhere(UserId, SessionId);
LogEveryoneElseOut(UserId, SessionId);

Simpan Sesi ID ke Sesi ["..."]

Sebelum semua ini, saya menyimpan SessionID ke koleksi Session di dalam AccountController, di dalam Login ([HttpPost]) metode:

if (Membership.ValidateUser(model.UserName, model.Password))
{
     Session["sessionid"] = System.Web.HttpContext.Current.Session.SessionID;
...

Kode Pengontrol

Saya kemudian menempatkan logika di dalam pengendali saya untuk mengontrol aliran pelaksanaan ketiga metode ini. Perhatikan di bawah ini bahwa jika karena alasan tertentu Session["sessionid"] aku s null, itu hanya akan menetapkan nilai "kosong". Ini untuk berjaga-jaga jika untuk beberapa alasan ia kembali sebagai null:

public ActionResult Index()
{
    if (Session["sessionid"] == null)
        Session["sessionid"] = "empty";

    // check to see if your ID in the Logins table has LoggedIn = true - if so, continue, otherwise, redirect to Login page.
    if (OperationContext.IsYourLoginStillTrue(System.Web.HttpContext.Current.User.Identity.Name, Session["sessionid"].ToString()))
    {
        // check to see if your user ID is being used elsewhere under a different session ID
        if (!OperationContext.IsUserLoggedOnElsewhere(System.Web.HttpContext.Current.User.Identity.Name, Session["sessionid"].ToString()))
        {
            return View();
        }
        else
        {
            // if it is being used elsewhere, update all their Logins records to LoggedIn = false, except for your session ID
            OperationContext.LogEveryoneElseOut(System.Web.HttpContext.Current.User.Identity.Name, Session["sessionid"].ToString());
            return View();
        }
    }
    else
    {
        FormsAuthentication.SignOut();
        return RedirectToAction("Login", "Account");
    }
}

Tiga Metode

Ini adalah metode yang saya gunakan untuk memeriksa apakah ANDA masih masuk (yaitu pastikan Anda tidak dikeluarkan oleh upaya masuk lain), dan jika demikian, periksa untuk melihat apakah User ID Anda masuk di tempat lain , dan jika demikian, usir mereka dengan hanya mengatur status LoggedIn mereka false di dalam tabel Login.

public static bool IsYourLoginStillTrue(string userId, string sid)
{
    CapWorxQuikCapContext context = new CapWorxQuikCapContext();

    IEnumerable<Logins> logins = (from i in context.Logins
                                  where i.LoggedIn == true && i.UserId == userId && i.SessionId == sid
                                  select i).AsEnumerable();
    return logins.Any();
}

public static bool IsUserLoggedOnElsewhere(string userId, string sid)
{
    CapWorxQuikCapContext context = new CapWorxQuikCapContext();

    IEnumerable<Logins> logins = (from i in context.Logins
                                  where i.LoggedIn == true && i.UserId == userId && i.SessionId != sid
                                  select i).AsEnumerable();
    return logins.Any();
}

public static void LogEveryoneElseOut(string userId, string sid)
{
    CapWorxQuikCapContext context = new CapWorxQuikCapContext();

    IEnumerable<Logins> logins = (from i in context.Logins 
                                  where i.LoggedIn == true && i.UserId == userId && i.SessionId != sid // need to filter by user ID
                                  select i).AsEnumerable();

    foreach (Logins item in logins)
    {
        item.LoggedIn = false;
    }

    context.SaveChanges();
}

EDIT Saya juga ingin menambahkan bahwa kode ini mengabaikan kemampuan fitur "Ingat Saya". Persyaratan saya tidak melibatkan fitur ini (pada kenyataannya, pelanggan saya tidak ingin menggunakannya, karena alasan keamanan) jadi saya hanya membiarkannya. Dengan beberapa pengkodean tambahan, saya cukup yakin bahwa ini dapat dipertimbangkan.


32
2018-04-11 02:51



Anda harus menyimpan informasi bahwa seseorang telah masuk ke dalam basis data. Ini akan memungkinkan Anda untuk memverifikasi apakah pengguna sudah memiliki sesi yang sudah ada. Di luar kotak modul otentikasi formulir di ASP.NET bekerja dengan cookie dan tidak ada cara bagi Anda untuk mengetahui di server apakah pengguna memiliki cookie di perangkat lain kecuali tentu saja Anda menyimpan informasi ini di server.


7
2018-04-09 13:44



Apa yang mungkin ingin Anda lakukan adalah ketika pengguna login, Anda menyimpan id sesi mereka di database di suatu tempat. Kemudian pada setiap halaman yang Anda akses, Anda harus memeriksa apakah id sesi saat ini sama dengan yang tersimpan dalam basis data, dan jika tidak Anda menandatanganinya.

Anda mungkin ingin membuat pengendali dasar yang melakukan ini dalam metode OnAuthorization atau OnActionExecuting. Pilihan lain adalah membuat filter Otorisasi Anda sendiri (saya lebih suka itu, sebenarnya, karena saya tidak suka kelas dasar umum seperti itu).

Dalam metode itu Anda akan mengakses database dan memeriksa id sesi.

Sadarilah bahwa itu tidak mudah dibasmi. Ada kemungkinan bagi seseorang untuk menyalin cookie sesi dan menyiasati ini, meskipun itu cukup jelas bahwa kebanyakan orang mungkin tidak akan tahu bagaimana melakukan itu, dan cukup menjengkelkan sehingga mereka yang tidak mau repot-repot.

Anda juga bisa menggunakan alamat IP, tapi itu kesepakatan yang sama. Dua orang di belakang proxy atau firewall nat akan tampak sebagai pengguna yang sama.


5
2018-04-09 13:47



Saya ingin menunjukkan bahwa alasan utama untuk pengaturan Session ["SessionID"] = "anything" adalah karena sampai Anda benar-benar menugaskan sesuatu ke objek sesi, ID sesi tampaknya terus berubah pada setiap permintaan.

Saya menemukan ini dengan beberapa perangkat lunak pengujian terpisah yang saya tulis.


1
2018-01-27 00:35



Berikut ini adalah metode yang sedikit lebih sederhana daripada jawaban yang diterima.

public static class SessionManager
    {
        private static List<User> _sessions = new List<User>();

        public static void RegisterLogin(User user)
        {
            if (user != null)
            {
                _sessions.RemoveAll(u => u.UserName == user.UserName);
                _sessions.Add(user);
            }
        }

        public static void DeregisterLogin(User user)
        {
            if (user != null)
                _sessions.RemoveAll(u => u.UserName == user.UserName && u.SessionId == user.SessionId);
        }

        public static bool ValidateCurrentLogin(User user)
        {
            return user != null && _sessions.Any(u => u.UserName == user.UserName && u.SessionId == user.SessionId);
        }
    }

    public class User {
        public string UserName { get; set; }
        public string SessionId { get; set; }
    }

Dengan ini, selama proses masuk Anda setelah Anda memverifikasi pengguna, Anda membuat instance dari kelas Pengguna dan menetapkan nama pengguna dan id sesi, simpan sebagai objek Sesi, lalu panggil fungsi RegisterLogin dengannya.

Kemudian, pada setiap pemuatan halaman, Anda mendapatkan objek sesi dan meneruskannya ke fungsi ValidateCurrentLogin.

Fungsi DeregisterLogin tidak benar-benar diperlukan, tetapi menyimpan objek _sessions sekecil mungkin.


0
2018-02-27 19:12