网上有很多介绍单点登录的文章,但多为架构设计以及概念性文章,而本文将介绍单点登录的具体具体实现

利用哈希表,作为保存登录用户的队列
        private static Hashtable m_userList;
设置用户在线超时的时限(我设置的是30分钟,可以根据自己的需求自行修改)
        private static TimeSpan m_tsSub = new TimeSpan(0, 30, 0);

设置哈希表初始化为同步封装(为了线程安全)
            m_userList = Hashtable.Synchronized(new Hashtable());

设置了几种方式

1、登录信息在数据库中验证成功后调用AddUserToList(string userName, long sessionID)

2、除登录外其他所有功能调用之前首先调用该方法 CheckUserLogin(string userName, long sessionID)

在第一种方式中,需要处理“如果用户已经登录过,则只更新登录流水号及操作时间,否则新加入队列"

该类还有个最重要的步骤就是检查保存在队列中的用户在线是否超过时限,该方法供线程调用,以便检查用户是否在线,需要保存待清理的超时在线用户的临时队列,线程每隔1分钟执行检查清理操作,遍历保存在线用户的哈希表,如果有超时的在线用户,将超时用户时放入临时的队列中,
检查完哈希表之后再进行清理操作,
不能在检查过程中执行哈希表的删除键值操作,否则会出现异常。

特别注意的是如果有超时的在线用户则进行清理操作

具体代码如下

using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Threading; namespace DllServiceLibrary
{
    class HashElement
    {
        long m_SessionID;
        DateTime m_Time;         public long SessionID
        {
            get { return m_SessionID; }
            set { m_SessionID = value; }
        }         public DateTime Time
        {
            get { return m_Time; }
            set { m_Time = value; }
        }         public HashElement()
        {
            m_SessionID = -1;
            m_Time = DateTime.Now;
        }
    }     public static class UserLogin
    {
        //哈希表,作为保存登录用户的队列
        private static Hashtable m_userList;
        //检查用户在线是否超时的线程
        //private static Thread m_threadQueue;
        //用户在线超时的时限(30分钟)
        private static TimeSpan m_tsSub = new TimeSpan(0, 30, 0);         //public static UserLogin()
        public static void Init()
        {
            //哈希表初始化为同步封装(线程安全)
            m_userList = Hashtable.Synchronized(new Hashtable());
            //初始化线程
            //m_threadQueue = new Thread(CheckListTO);
            //m_threadQueue.IsBackground = true;  //设置为后台线程
            //m_threadQueue.Start();
        }         public static void Empty()
        {
            //if (m_threadQueue.IsAlive)
            //{
            //    m_threadQueue.Abort();
            //}
            m_userList.Clear();
        }         /// <summary>
        /// 登录信息在数据库中验证成功后调用
        /// </summary>
        /// <param name="userName">用户名</param>
        /// <param name="sessionID">登录流水号</param>
        /// <returns>
        /// 0:用户及登录流水号成功保存于队列
        /// -1:保存失败
        /// </returns>
        public static int AddUserToList(string userName, long sessionID)
        {
            WriteLog.WriteData w = new WriteLog.WriteData();
            int ret = 0;
            try
            {
                HashElement hashElt = new HashElement();
                hashElt.SessionID = sessionID;
                //如果用户已经登录过,则只更新登录流水号及操作时间,否则新加入队列
                lock (m_userList.SyncRoot)
                {
                    if (m_userList.ContainsKey(userName))
                    {
                        m_userList[userName] = hashElt;
                    }
                    else
                    {
                        m_userList.Add(userName, hashElt);
                    }
                }
            }
            catch (Exception exp)
            {
                //System.Console.Out.WriteLine(exp.StackTrace);
                //System.Console.Out.WriteLine(exp.Message);
                w.WriteLine(exp.Message + exp.StackTrace, 01);
                ret = -1;
            }
            return ret;
        }         /// <summary>
        /// 除登录外其他所有功能调用之前首先调用该方法
        /// </summary>
        /// <param name="userName">用户名</param>
        /// <param name="sessionID">登录流水号</param>
        /// <returns>
        /// 0:验证用户登录成功
        /// -1:验证用户登录失败
        /// -2:用户未登录
        /// -3:用户已重新登录或在别处登录
        /// </returns>
        public static int CheckUserLogin(string userName, long sessionID)
        {
            //WriteLog.WriteData w = new WriteLog.WriteData();
            int ret = 0;
            try
            {
                lock (m_userList.SyncRoot)
                {
                    if (m_userList.ContainsKey(userName))
                    {
                        HashElement hashElt = m_userList[userName] as HashElement;
                        if (hashElt.SessionID.Equals(sessionID))
                        {
                            hashElt.Time = DateTime.Now;
                            m_userList[userName] = hashElt;
                            ret = 0;
                        }
                        else
                        {
                            ret = -3;
                        }
                    }
                    else
                    {
                        ret = -2;
                    }
                }
            }
            catch 
            {
                //w.WriteLine(exp.Message + exp.StackTrace, 02);
                //System.Console.Out.WriteLine(exp.StackTrace);
                //System.Console.Out.WriteLine(exp.Message);
                ret = -1;
            }
            return ret;
        }         /// <summary>
        /// 检查保存在队列中的用户在线是否超过时限,该方法供线程调用
        /// </summary>
        private static void CheckListTO()
        {
            //WriteLog.WriteData w = new WriteLog.WriteData();
            try
            {
                //保存待清理的超时在线用户的临时队列
                List<string> toKeys = new List<string>();
                while (true)
                {
                    //线程每隔1分钟执行检查清理操作
                    Thread.Sleep(1000 * 60);
                    //遍历保存在线用户的哈希表
                    lock (m_userList.SyncRoot)
                    {
                        foreach (DictionaryEntry deElt in m_userList)
                        {
                            //如果有超时的在线用户,将超时用户时放入临时的队列中,
                            //检查完哈希表之后再进行清理操作
                            //不能在检查过程中执行哈希表的删除键值操作,否则会出现异常。
                            HashElement htElt = deElt.Value as HashElement;
                            if (DateTime.Now - htElt.Time > m_tsSub)
                            {
                                toKeys.Add((string)deElt.Key);
                            }
                        }
                        //如果有超时的在线用户则进行清理操作
                        if (0 < toKeys.Count)
                        {
                            foreach (string key in toKeys)
                            {
                                m_userList.Remove(key);
                            }
                            toKeys.Clear();
                        }
                    }
                }
            }
            catch 
            {
                //System.Console.Out.WriteLine(exp.StackTrace);
                //System.Console.Out.WriteLine(exp.Message);
                //w.WriteLine(exp.Message + exp.StackTrace, 03);
            }
        }         /// <summary>
        /// 获取当前在线用户统计数
        /// </summary>
        /// <returns>统计数</returns>
        public static int GetUserCount()
        {
          //WriteLog.WriteData w = new WriteLog.WriteData();
            int count = 0;
            try
            {
                lock (m_userList.SyncRoot)
                {
                    count = m_userList.Count;
                }
            }
            catch 
            {
                //System.Console.Out.WriteLine(exp.StackTrace);
                //System.Console.Out.WriteLine(exp.Message);
                //w.WriteLine(exp.Message + exp.StackTrace, 04);
            }
            return count;
        }
    }
}

C#实现支持单点登录的一个存储用户信息的类的更多相关文章

  1. python实现用户登陆(sqlite数据库存储用户信息)

    python实现用户登陆(sqlite数据库存储用户信息) 目录 创建数据库 数据库管理 简单登陆 有些地方还未完善. 创建数据库 import sqlite3 #建一个数据库 def create_ ...

  2. C# 脚本代码自动登录淘宝获取用户信息

    C# 脚本代码自动登录淘宝获取用户信息   最近遇到的一个需求是如何让程序自动登录淘宝, 获取用户名称等信息. 其实这个利用SS (SpiderStudio的简称) 实现起来非常简单. 十数行代码就可 ...

  3. php 微信登录 公众号 获取用户信息 微信网页授权

    php 微信登录 公众号 获取用户信息 微信网页授权 先自己建立两个文件: index.php  和  getUserInfo.php index.php <?php //scope=snsap ...

  4. CAS单点登录之mysql数据库用户验证及常见问题

    前面已经介绍了CAS服务器的搭建,详情见:搭建CAS单点登录服务器.然而前面只是简单地介绍了服务器的搭建,其验证方式是原始的配置文件的方式,这显然不能满足日常的需求.下面介绍下通过mysql数据库认证 ...

  5. 微信小程序维护登录态与获取用户信息

    前言. 微信小程序的运行环境不是在浏览器下运行的.所以不能以cookie来维护登录态.下面我就来说说我根据官方给出的方法来写出的维护登录态的方法吧. 一.登录态维护 官方的文档地址:https://m ...

  6. Cas单点登录配置数据查询用户

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  7. 【转】如何打开注册表编辑器中存储用户信息的SAM文件?

    sam文件怎么打开 (Security Accounts Manager安全帐户管理器)负责SAM数据库的控制和维护.SAM数据库位于注册表HKLM\SAM\SAM下,受到ACL保护,可以使用rege ...

  8. 微信订阅号里实现oauth授权登录,并获取用户信息 (完整篇)

    摘要 这段时间一直有人问我,订阅号实现的oauth授权登录的问题,之前写的比较简单,很多人不明白.众所周知,微信公众号分订阅号.服务号.企业号:每个号的用途不一样,接口开放程度也不一样.微信还有个扯淡 ...

  9. Shiro与CAS整合实现单点登录

    1.简介 CAS:Yale 大学发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的单点登录方法. Shiro:Apache Shiro是一个Java安全框架,可以帮助我们完成认证.授权.会话管 ...

随机推荐

  1. CentOS7.1下生产环境Keepalived+Nginx配置

    CentOS7.1下生产环境Keepalived+Nginx配置 [日期:2015-07-20] 来源:Linux社区  作者:soulful [字体:大 中 小]   注:下文涉及到配置的,如无特别 ...

  2. phpstorm xdebug

    xdebug安装 https://xdebug.org/wizard.php http://blog.csdn.net/zhyh1986/article/details/45172685 http:/ ...

  3. 【JSP中引入文件】JSP中获取根路径+引用js文件

    在jsp界面中经常需要引入js.css等文件,通常都需要先获取项目根路径,然后再引入文件. 例如: 项目路径如下,需要在index.jsp中引入FusionCharts相关的js.css等: inde ...

  4. OS信号实现Java异步通知

    OS信号实现Java异步通知本文将结合操作系统的信号机制,来尝试实现一个简单的,不依赖功能环境的Java异步通知功能.没有特殊说明,本文所有的示例,都是基于Linux.信号简介信号是在软件层次上对中断 ...

  5. Eclipse修改workspace目录的几种方式

    Eclipse是一款很强的Java IDE,我们在开始的时候,往往设定了默认的workspace,当用久在之后,我们可能要去更改一下workspace的位置.下面有几种方法可以更改workspace的 ...

  6. python学习菜单

    一.python简介 二.python字符串 三.列表 四.集合.元组.字典 五.函数 六.python 模块 七.python 高阶函数 八.python 装饰器 九.python 迭代器与生成器  ...

  7. Maven 添加jdk编译插件

    问题描述: 默认情况下,eclipse的maven项目使用jdk1.5编译,而我们的jdk为1.8每次更改jdk1.5之后,只要maven项目已更新,eclipse就会自动的回到jdk1.8结局方法: ...

  8. C# 方法中带默认值的参数

    设计一个方法的参数时,可为部分或全部参数分配默认值.然后,调用这些方法的代码可以选择不指定部分实参,接受其默认值.除此之外,调用方法时,还可通过指定参数名称的方式为其传递实参.以下代码演示了可选参数和 ...

  9. jQuery实现todo及轮播图

    内容: 1.todo程序 2.轮播图 1.todo程序 需求: 实现一个todo程序,可以添加数据,可以删除数据,可以修改数据,可以查看所有数据 另外实现自己的一系列弹窗:用于提示用户的提示框.用于警 ...

  10. 用dataset保存数据注意的问题

    Private Function Save() As Boolean Try Dim dschgs As DataSet = ds.GetChanges(DataRowState.Added + Da ...