原文:
SignOnMode.cs
#region // ----------------------------------------------------------------- // 版权所有:Copyright(C) // 文件名称:SignOnMode.cs // 系统名称: // 模块名称: // 作 者:Keasy5 // 完成日期:2015/12/24 9:51:10 // 功能描述: // ----------------------------------------------------------------- // 修 改 者: // 修改日期: // 修改描述: // ----------------------------------------------------------------- #endregion using System; using System.Collections; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web; using DocumentFormat.OpenXml.Packaging; namespace Common.Function.Login { /// <summary> /// 登录方式类 /// </summary> /// <remarks> /// 同一账号是否能在多处登录帮助类 /// </remarks> public static class SignOnMode { /// <summary> /// 在线信息Application标识 /// </summary> private const string OnlineAppFlag = "Online"; private const string InvalidSessionFlag = "INVALIDSESSION"; /// <summary> /// 添加登录信息 /// </summary> /// <param name="signOnToken"> /// 登录令牌:用于标识用户信息的唯一标识,一般是用户的id /// </param> public static void RegisterSignOn(string signOnToken) { Hashtable hOnline = (Hashtable)HttpContext.Current.Application[OnlineAppFlag]; if (hOnline != null) { IDictionaryEnumerator enumerator = hOnline.GetEnumerator(); string sessionId = ""; while (enumerator.MoveNext()) { if (enumerator.Value != null && enumerator.Value.ToString().Equals(signOnToken)) { /* * 将当前用户Id对应的会话(Session.SessionID唯一标识) * 都设置为无效会话 */ sessionId = enumerator.Key.ToString(); hOnline[sessionId] = InvalidSessionFlag; //无效会话 break; } } } else { hOnline = new Hashtable(); } //将当前"登录"用户Id对应的会话设置为有效会话 hOnline[HttpContext.Current.Session.SessionID] = signOnToken; HttpContext.Current.Application.Lock(); HttpContext.Current.Application[OnlineAppFlag] = hOnline; HttpContext.Current.Application.UnLock(); } /// <summary> /// 是否需要强制退出当前登录 /// </summary> /// <returns> /// 是否退出登录: /// true:表示当前登录需要当前强制退出 /// 否则:当前当前登录不需要退出 /// </returns> public static bool NeedForceSignOut() { bool needForcedSignOut = false; //是否需要强制退出当前登录 // 配置:同一账号是否能在多处登录 string canMultipleLogin = ConfigurationManager.AppSettings["CanMultipleLogin"]; if (canMultipleLogin != null && canMultipleLogin.ToLower() == "true") { return false; //同一账号可以能在多处登录 } Hashtable hOnline = (Hashtable)HttpContext.Current.Application[OnlineAppFlag]; if (hOnline != null && HttpContext.Current.Session != null) { IDictionaryEnumerator enumerator = hOnline.GetEnumerator(); while (enumerator.MoveNext()) { var sessionId = enumerator.Key; var sessionVal = enumerator.Value; if (sessionId != null && sessionId.ToString().Equals(HttpContext.Current.Session.SessionID)) { if (sessionVal != null && InvalidSessionFlag.Equals(sessionVal.ToString())) { /*删除无效会话*/ hOnline.Remove(HttpContext.Current.Session.SessionID); HttpContext.Current.Application.Lock(); HttpContext.Current.Application[OnlineAppFlag] = hOnline; HttpContext.Current.Application.UnLock(); //帐号已在别处登陆,被强迫下线! needForcedSignOut = true; } break; } } } return forcedSignOut; } /// <summary> /// 清除无效登录信息 /// </summary> /// <remarks> /// 一般用于Global.asax.cs的函数: /// protected void Session_End(object sender, EventArgs e) /// 中调用,使得在Session过期或者退出系统时释放资源 /// </remarks> public static void ClearInvalidSignOn() { if (HttpContext.Current != null) { Hashtable hOnline = (Hashtable)HttpContext.Current.Application[OnlineAppFlag]; if (hOnline != null) { if (HttpContext.Current.Session != null) { if (hOnline[HttpContext.Current.Session.SessionID] != null) { hOnline.Remove(HttpContext.Current.Session.SessionID); HttpContext.Current.Application.Lock(); } } } } } } }
文件:SessionKeys.cs
/// <summary> /// 系统级别Session名称 /// </summary> public static class SessionKeys { /// <summary> /// 存储用户登录的session名常量 /// </summary> public const string LoginUser = "LoginUser"; }
文件SessionHelper.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web; namespace xxxx { /// <summary> /// Session 操作类 /// 1、GetSession(string name)根据session名获取session对象 /// 2、SetSession(string name, object val)设置session /// </summary> public class SessionHelper { /// <summary> /// 根据session名获取session对象 /// </summary> /// <param name="name"></param> /// <returns></returns> public static object GetSession(string name) { return HttpContext.Current.Session[name]; } /// <summary> /// 设置session /// </summary> /// <param name="name">session 名</param> /// <param name="val">session 值</param> public static void SetSession(string name, object val) { if (KeysContains(name)) { HttpContext.Current.Session[name] = val; } else { HttpContext.Current.Session.Add(name, val); } } /// <summary> /// 判断Key值在当前Session是不是已经存在 /// </summary> /// <param name="key"></param> /// <returns></returns> private static bool KeysContains(string key) { if (HttpContext.Current.Session != null) { foreach (var item in HttpContext.Current.Session.Keys) { if (item != null && item.Equals(key)) return true; } } return false; } /// <summary> /// 添加Session,调动有效期为20分钟 /// </summary> /// <param name="strSessionName">Session对象名称</param> /// <param name="strValue">Session值</param> public static void Add(string strSessionName, object strValue) { HttpContext.Current.Session[strSessionName] = strValue; HttpContext.Current.Session.Timeout = 120; } /// <summary> /// 添加Session,调动有效期为20分钟 /// </summary> /// <param name="strSessionName">Session对象名称</param> /// <param name="strValues">Session值数组</param> public static void Adds(string strSessionName, string[] strValues) { HttpContext.Current.Session[strSessionName] = strValues; HttpContext.Current.Session.Timeout = 120; } /// <summary> /// 添加Session /// </summary> /// <param name="strSessionName">Session对象名称</param> /// <param name="strValue">Session值</param> /// <param name="iExpires">调动有效期(分钟)</param> public static void Add(string strSessionName, object strValue, int iExpires) { HttpContext.Current.Session[strSessionName] = strValue; HttpContext.Current.Session.Timeout = iExpires; } /// <summary> /// 添加Session /// </summary> /// <param name="strSessionName">Session对象名称</param> /// <param name="strValues">Session值数组</param> /// <param name="iExpires">调动有效期(分钟)</param> public static void Adds(string strSessionName, string[] strValues, int iExpires) { HttpContext.Current.Session[strSessionName] = strValues; HttpContext.Current.Session.Timeout = iExpires; } /// <summary> /// 读取某个Session对象值 /// </summary> /// <param name="strSessionName">Session对象名称</param> /// <returns>Session对象值</returns> public static string Get(string strSessionName) { if (HttpContext.Current.Session[strSessionName] == null) { return null; } else { return HttpContext.Current.Session[strSessionName].ToString(); } } /// <summary> /// 读取某个Session对象值数组 /// </summary> /// <param name="strSessionName">Session对象名称</param> /// <returns>Session对象值数组</returns> public static string[] Gets(string strSessionName) { if (HttpContext.Current.Session[strSessionName] == null) { return null; } else { return (string[])HttpContext.Current.Session[strSessionName]; } } /// <summary> /// 删除某个Session对象 /// </summary> /// <param name="strSessionName">Session对象名称</param> public static void Del(string strSessionName) { HttpContext.Current.Session[strSessionName] = null; } /// <summary> /// 获取Session 过期时间 /// </summary> /// <returns></returns> public static int SessionTimeout(string sessionTimeoutConfigString) { string sessionTimeout = sessionTimeoutConfigString; if (string.IsNullOrWhiteSpace(sessionTimeout)) { //如果为空,默认30 return 30; } return Convert.ToInt32(sessionTimeout); } } }
使用:
第一步:在登录成功后,记录登录信息
SignOnMode.RegisterSignOn(user.Id);
public string Login(LoginViewModel model,bool rememberAccount) { //....... if(登录成功) {
HttpContext.Current.Session[SessionKeys.LoginUser] = ....;//用户登录信息,如果该值为null,视为没有登录
SignOnMode.RegisterSignOn(user.Id);
}
//.......
}
第二步:
在需要登录的地方执行
bool forcedLogout = SignOnMode.NeedForceSignOut();
这里是定义个筛选器,然后在使用在Controller上。
public override void OnActionExecuting(ActionExecutingContext filterContext) { var _url = "~/Home/Index"; if (HttpContext.Current.Session[SessionKeys.LoginUser] == null) { filterContext.Result = new RedirectResult(_url); } else { #region 同一账号不能多处登录 /*-------------------------------------------------------------------------- 同一账号不能多处登录 *--------------------------------------------------------------------------*/ bool needForceSignOut = SignOnMode.NeedForceSignOut(); if (needForceSignOut) {
HttpContext.Current.Session[SessionKeys.LoginUser] = null; //用户登录信息,如果该值为null,视为没有登录 filterContext.Result = new RedirectResult(_url); } #endregion } }
[LoginFilter] public class BaseController : Controller { ...... }
第三步:在Session过期或者(异常)退出系统时,释放资源释放资源,做法是:
在Global.asax.cs的函数:
protected void Session_End(object sender, EventArgs e)
中调用:
SignOnMode.ClearInvalidSignOn();
使得在Session过期或者退出系统时释放资源
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() {
....
} protected void Session_End(object sender, EventArgs e) { /*-------------------------------------------------------------------------- 同一账号不能多处登录 *--------------------------------------------------------------------------*/ /*在Session过期或者退出系统时释放资源*/ SignOnMode.ClearInvalidSignOn(); } }
第四步:
在配置文件添加中添加“同一账号是否能多处登录”的开关。
<appSettings> <!--配置:同一账号是否能多处登录,true表示可以多点登陆--> <add key="CanMultipleLogin" value="false" /> </appSettings>
完毕。