项目中使用了通用权限管理系统,该系统集成了单点登录功能,下面我来介绍下该单点登录实现的一些细节。
首先我们来看看其登录接口,系统本身支持各种登录方式:
1、公司名、用户名、密码
2、唯一账号、密码
3、手机号码、密码
5、Email、密码
接口已实现的部分功能:
C/S客户端登录还可以检测MAC地址,
B/S的可以对IP进行检查;
可在用户登录地址发生变化后进行手机验证后才能继续登录;
每次登陆都会记录登录日志;
。。。
另外,根据需要,可在登录接口扩展其它功能,我在项目中就增加了登录提醒功能,每次登陆都会发送提醒信息到用户的手机、微信或邮箱中。
登录后,会对应该用户生成一个OpenId,该OpenId是一个GUID,看看代码部分截图:
具体生成OPenId的地方,生成OpenID使用了一个线程,这样可加快登录接口的速度。
实现部分的功能代码
1 public void UpdateVisitDateTask(object param) 2 { 3 var tuple = param as Tuple<BaseUserLogOnEntity, bool, string>; 4 BaseUserLogOnEntity userLogOnEntity = tuple.Item1; 5 bool createOpenId = tuple.Item2; 6 string openId = tuple.Item3; 7 8 // 2015-01-06 提高效率,写入缓存 9 if (BaseSystemInfo.UserCenterDbType == CurrentDbType.Oracle) 10 { 11 DotNet.Business.Utilities.SetUserOpenId(userLogOnEntity.Id, openId); 12 } 13 14 string sqlQuery = string.Empty; 15 DateTime? openIdTimeout = DateTime.Now.AddHours(8); 16 17 IDbHelper dbHelper = DbHelperFactory.GetHelper(BaseSystemInfo.UserCenterDbType, BaseSystemInfo.UserCenterDbConnection); 18 // 是否更新访问日期信息 19 List<IDbDataParameter> dbParameters = new List<IDbDataParameter>(); 20 21 // 若有一周没登录了,需要重新进行手机验证 22 bool mobileValiated = false; 23 if (userLogOnEntity.PreviousVisit.HasValue || userLogOnEntity.FirstVisit.HasValue) 24 { 25 TimeSpan ts = new System.TimeSpan(); 26 if (userLogOnEntity.LastVisit.HasValue) 27 { 28 ts = DateTime.Now.Subtract((DateTime)userLogOnEntity.LastVisit); 29 mobileValiated = (ts.TotalDays > 7); 30 } 31 else if (userLogOnEntity.FirstVisit.HasValue) 32 { 33 ts = DateTime.Now.Subtract((DateTime)userLogOnEntity.FirstVisit); 34 mobileValiated = (ts.TotalDays > 7); 35 } 36 if (mobileValiated) 37 { 38 sqlQuery = " UPDATE " + BaseUserContactEntity.TableName 39 + " SET " + BaseUserContactEntity.FieldMobileValiated + " = 0 " 40 + " WHERE " + BaseUserContactEntity.FieldId + " = '" + userLogOnEntity.Id + "' AND " + BaseUserContactEntity.FieldMobileValiated + " = 1 "; 41 dbHelper.ExecuteNonQuery(sqlQuery); 42 } 43 } 44 45 if (BaseSystemInfo.UpdateVisit) 46 { 47 // 第一次登录时间 48 if (userLogOnEntity.FirstVisit == null) 49 { 50 sqlQuery = " UPDATE " + BaseUserLogOnEntity.TableName 51 + " SET " + BaseUserLogOnEntity.FieldPasswordErrorCount + " = 0 , " 52 + " " + BaseUserLogOnEntity.FieldUserOnLine + " = 1 " 53 + ", " + BaseUserLogOnEntity.FieldFirstVisit + " = " + dbHelper.GetDbNow() 54 + ", " + BaseUserLogOnEntity.FieldIPAddress + " = '" + userLogOnEntity.IPAddress + "'" 55 + ", " + BaseUserLogOnEntity.FieldIPAddressName + " = '" + userLogOnEntity.IPAddressName + "'" 56 + ", " + BaseUserLogOnEntity.FieldMACAddress + " = '" + userLogOnEntity.MACAddress + "'" 57 + ", " + BaseUserLogOnEntity.FieldSystemCode + " = " + dbHelper.GetParameter(BaseUserLogOnEntity.FieldSystemCode); 58 dbParameters.Add(dbHelper.MakeParameter(BaseUserLogOnEntity.FieldSystemCode, userLogOnEntity.SystemCode)); 59 60 if (createOpenId) 61 { 62 sqlQuery += " , " + BaseUserLogOnEntity.FieldOpenId + " = '" + openId + "'"; 63 sqlQuery += " , " + BaseUserLogOnEntity.FieldOpenIdTimeout + " = " + dbHelper.GetParameter(BaseUserLogOnEntity.FieldOpenIdTimeout); 64 dbParameters.Add(dbHelper.MakeParameter(BaseUserLogOnEntity.FieldOpenIdTimeout, openIdTimeout)); 65 } 66 67 sqlQuery = sqlQuery + " WHERE (" + BaseUserLogOnEntity.FieldId + " = '" + userLogOnEntity.Id + "') AND " + BaseUserLogOnEntity.FieldFirstVisit + " IS NULL"; 68 dbHelper.ExecuteNonQuery(sqlQuery, dbParameters.ToArray()); 69 } 70 else 71 { 72 // 最后一次登录时间 73 sqlQuery = " UPDATE " + BaseUserLogOnEntity.TableName 74 + " SET " + BaseUserLogOnEntity.FieldPasswordErrorCount + " = 0 , " 75 + BaseUserLogOnEntity.FieldPreviousVisit + " = " + BaseUserLogOnEntity.FieldLastVisit + " , " 76 + BaseUserLogOnEntity.FieldUserOnLine + " = 1 , " 77 + BaseUserLogOnEntity.FieldLastVisit + " = " + dbHelper.GetDbNow() + " , " 78 + BaseUserLogOnEntity.FieldLogOnCount + " = " + BaseUserLogOnEntity.FieldLogOnCount + " + 1 " 79 + ", " + BaseUserLogOnEntity.FieldSystemCode + " = " + dbHelper.GetParameter(BaseUserLogOnEntity.FieldSystemCode) 80 + ", " + BaseUserLogOnEntity.FieldIPAddress + " = '" + userLogOnEntity.IPAddress + "'" 81 + ", " + BaseUserLogOnEntity.FieldIPAddressName + " = '" + userLogOnEntity.IPAddressName + "'" 82 + ", " + BaseUserLogOnEntity.FieldMACAddress + " = '" + userLogOnEntity.MACAddress + "'"; 83 dbParameters.Add(dbHelper.MakeParameter(BaseUserLogOnEntity.FieldSystemCode, userLogOnEntity.SystemCode)); 84 85 if (createOpenId) 86 { 87 sqlQuery += " , " + BaseUserLogOnEntity.FieldOpenId + " = '" + openId + "'"; 88 sqlQuery += " , " + BaseUserLogOnEntity.FieldOpenIdTimeout + " = " + dbHelper.GetParameter(BaseUserLogOnEntity.FieldOpenIdTimeout); 89 dbParameters.Add(dbHelper.MakeParameter(BaseUserLogOnEntity.FieldOpenIdTimeout, openIdTimeout)); 90 } 91 92 sqlQuery += " WHERE (" + BaseUserLogOnEntity.FieldId + " = '" + userLogOnEntity.Id + "')"; 93 dbHelper.ExecuteNonQuery(sqlQuery, dbParameters.ToArray()); 94 } 95 } 96 else 97 { 98 // 实现单点登录功能,每次都更换Guid 99 if (createOpenId) 100 { 101 sqlQuery = " UPDATE " + BaseUserLogOnEntity.TableName 102 + " SET " + BaseUserLogOnEntity.FieldPasswordErrorCount + " = 0 " 103 + " , " + BaseUserLogOnEntity.FieldSystemCode + " = " + dbHelper.GetParameter(BaseUserLogOnEntity.FieldSystemCode) 104 + " , " + BaseUserLogOnEntity.FieldOpenId + " = '" + openId + "'" 105 + " , " + BaseUserLogOnEntity.FieldOpenIdTimeout + " = " + dbHelper.GetParameter(BaseUserLogOnEntity.FieldOpenIdTimeout) 106 + " WHERE (" + BaseUserLogOnEntity.FieldId + " = " + userLogOnEntity.Id + ")"; 107 // sqlQuery += " AND " + BaseUserEntity.FieldOpenId + " IS NULL "; 108 dbParameters.Add(dbHelper.MakeParameter(BaseUserLogOnEntity.FieldSystemCode, userLogOnEntity.SystemCode)); 109 dbParameters.Add(dbHelper.MakeParameter(BaseUserLogOnEntity.FieldOpenIdTimeout, openIdTimeout)); 110 111 dbHelper.ExecuteNonQuery(sqlQuery, dbParameters.ToArray()); 112 } 113 } 114 }
以上是登录部分功能的实现,其它系统登录时,根据OpenId进行登录。那么这里的Openid怎么调用呢?
如果是C/s系统,Openid是可以直接获取到的。在访问子系统时带上该OpenId,子系统再通过OpenId登录接口实现登录。
如果是B/S系统,有另外的实现方法,可在系统功能中找到。
下图是其它系通过通过OpenId登录的功能截图
Utilities.LogOnByOpenId(openId, true) 是通用权限管理系统底层已经实现好的方法,子系统直接调用DLL即可。
以上是通用权限系统实现的单点登录功能介绍,主要是通过OpenId进行的,可根据具体业务场景进行扩展,
对于此种方法实现的单点登录功能,大家有什么建议,欢迎交流。