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

利用哈希表,作为保存登录用户的队列
        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. sqlvarchar后自动填充空格解决办法(SET ANSI_PADDING)

    SET ANSI_PADDING http://www.yesky.com/imagesnew/software/tsql/ts_set-set_2uw7.htm http://www.makaido ...

  2. vim配置之目录结构

    我喜欢作配置分离,这样比较好管理,这里直接贴一下tree的目录结构 xxx@debian:~/vimConfig$ tree . ├── install │   ├── install.sh │   ...

  3. js jquery 设置cookie

    转自http://yaoqianglilan.blog.163.com/blog/static/70978316201091810435251/ 本人亲测setcookie() getcookie() ...

  4. 异步FIFO空满设计延迟问题

    由于设计的时候读写指针用了至少两级寄存器同步,同步会消耗至少两个时钟周期,势必会使得判断空或满有所延迟,这会不会导致设计出错呢? 异步FIFO通过比较读写指针进行满空判断,但是读写指针属于不同的时钟域 ...

  5. bzoj2458 最小三角形

    Description Xaviera现在遇到了一个有趣的问题.平面上有N个点,Xaviera想找出周长最小的三角形.由于点非常多,分布也非常乱,所以Xaviera想请你来解决这个问题.为了减小问题的 ...

  6. 设置UMG的ComboBox(String)字体大小

    转自:http://aigo.iteye.com/blog/2295448 UMG自带ComboBox组件没有提供直接的属性来修改其字体大小,只能自己做一个列表类型的widget然后再塞进ComboB ...

  7. 【转载】Docker 经验之谈

    本文来源:Ghostcloud原创     对于用户来说,可能一开始在不了解的情况下会对容器报以拒绝的态度,但是在尝到容器的甜头.体验到它的强大性能之后,相信大家最终是无法抵挡其魅力的.容器技术能够解 ...

  8. Java 类的生命周期

    类从被加载到JVM内存中开始,到卸载出内存为止,它的整个生命周期包括: 加载(Loading)-->验证(Verification)-->准备(Preparation)-->解析(R ...

  9. 批处理框架-spring Batch

    并发处理业务 数据量大,并发度高,要支持事物,回滚,并发机制.事务.并发.监控.执行等,并不提供相应的调度功能.因此,如果我们希望批处理任务定期执行,可结合 Quartz 等成熟的调度框架实现. 业务 ...

  10. ExtJS自定义事件

    1.开发ExtJS组件UI的时候,基本上对于一些操作,就是与后台交互之类的多数都是用户进行点击触发一个事件,在事件的处理器handler里面调具体的业务方法,完成业务数据的处理以及业务流程的流转机制, ...