单点登录问题
1.单点登录SSO实现原理:
多个客户端到统一的一个服务器端进行验证;服务器根据客户端的令牌,找到对应的凭证,返回给客户端,告诉客户端是否可以进行访问。
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Data; namespace Example_SSO.Class { /// <summary> /// 缓存管理 /// 把令牌和主站凭证关系存入缓存 /// </summary> public class CacheManager { /// <summary> /// 获取缓存中的table /// </summary> /// <returns></returns> public static DataTable GetCacheTable() { DataTable dt = null; if (HttpContext.Current.Cache["CERT"] != null) { dt =(DataTable) HttpContext.Current.Cache["CERT"]; } return dt; } /// <summary> /// 初始化数据结构 /// </summary> /// <remarks> /// ---------------------------------------------------- /// | token(令牌) | info(用户凭证) | timeout(过期时间) | /// |--------------------------------------------------| /// </remarks> public static void CacheInit() { if (HttpContext.Current.Cache["CERT"] == null) { DataTable dt = new DataTable(); dt.Columns.Add("token", Type.GetType("System.String")); dt.Columns["token"].Unique = true; dt.Columns.Add("info", Type.GetType("System.Object")); dt.Columns["info"].DefaultValue = null; dt.Columns.Add("timeout", Type.GetType("System.DateTime")); dt.Columns["timeout"].DefaultValue=DateTime.Now.AddMinutes(double.Parse(System.Configuration.ConfigurationManager.AppSettings["timeout"])); DataColumn[] keys = new DataColumn[1]; keys[0] = dt.Columns["token"]; dt.PrimaryKey = keys; //cache 的过期时间为 令牌时间的2倍 HttpContext.Current.Cache.Insert("CERT", dt,null, DateTime.MaxValue, TimeSpan.FromMinutes(double.Parse(System.Configuration.ConfigurationManager.AppSettings["timeout"]) * 2)); } } /// <summary> /// 判断令牌是否存在 /// </summary> /// <param name="token"></param> /// <returns></returns> public static bool TokenIsExist(string token) { CacheInit(); DataTable dt = (DataTable)HttpContext.Current.Cache["CERT"]; if (dt.Select("token='" + token + "'").Length == 0)//令牌不存在 { return false; } else //令牌存在 { return true; } } /// <summary> /// 更新令牌时间 /// </summary> /// <param name="token"></param> /// <param name="time"></param> public static void tokenTimeUpdate(string token, DateTime time) { CacheInit(); DataTable dt = (DataTable)HttpContext.Current.Cache["CERT"]; DataRow[] dr = dt.Select("token='"+token+"'"); if (dr.Length > 0) { dr[0]["timeout"] = time; } } /// <summary> /// 添加令牌 /// </summary> /// <param name="token"></param> /// <param name="info"></param> /// <param name="time"></param> public static void TokenInsert(string token, object info, DateTime timeout) { CacheInit(); if (!TokenIsExist(token))//不存在 { DataTable dt = (DataTable)HttpContext.Current.Cache["CERT"]; DataRow dr = dt.NewRow(); dr["Token"] = token; dr["info"] = info; dr["timeout"] = timeout; dt.Rows.Add(dr); HttpContext.Current.Cache["CERT"] = dt; } else { tokenTimeUpdate(token, timeout); } } } }
服务器的服务:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Services; using System.Data; using Example_SSO.Class; namespace Example_SSO { /// <summary> /// TokenService 的摘要说明 /// </summary> [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.ComponentModel.ToolboxItem(false)] // 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。 // [System.Web.Script.Services.ScriptService] public class TokenService : System.Web.Services.WebService { [WebMethod] public string HelloWorld() { return "Hello World"; } /// <summary> /// 获取令牌的对应凭证 /// </summary> /// <param name="token"></param> /// <returns></returns> [WebMethod] public object TokenGetGredence(string token) { object o = new object(); DataTable dt = Example_SSO.Class.CacheManager.GetCacheTable(); if (dt != null) { DataRow[] dr = dt.Select("token='" + token + "'"); if (dr.Length > 0) { o = dr[0]["info"]; } } return o; } /// <summary> /// 清除令牌 /// </summary> /// <param name="token"></param> [WebMethod] public static void TokenClear(string token) { DataTable dt = Example_SSO.Class.CacheManager.GetCacheTable(); if (dt != null) { DataRow[] dr = dt.Select("token='"+token+"'"); if (dr.Length > 0) { dt.Rows.Remove(dr[0]); } } } } }
2.客户端通过调用服务器的服务来验证令牌
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Text.RegularExpressions; namespace SiteA.Class { //授权页面基类 public class AuthBase : System.Web.UI.Page { protected override void OnLoad(EventArgs e) { // base.OnLoad(e); if (Session["Token"] != null) { //凭证存在 Response.Write("恭喜你,凭证存在"); } else { //令牌验证结果 if (Request.QueryString["Token"] != null) { if (Request.QueryString["Token"] != "$Token$") { //持有令牌 string tokenvalue = Request.QueryString["Token"].ToString(); //调用凭证验证服务,获取令牌对应的凭证 Example_SSO.TokenService tokenService = new Example_SSO.TokenService(); object o = tokenService.TokenGetGredence(tokenvalue); if (o != null) { //令牌正确 Session["Token"] = o; Response.Write("恭喜你,令牌存在"); } else { Response.Write("令牌错误"); } } else { Response.Write("未持有令牌"); } } else { Response.Redirect(this.getTokenURL()); } } base.OnLoad(e); } /// <summary> /// 获取带令牌请求的url /// </summary> /// <returns></returns> public string getTokenURL() { string url = Request.Url.AbsoluteUri; Regex reg = new Regex(@"^.*\?.+=.+$"); if (reg.IsMatch(url)) { url += "$Token=$Token$"; } else { url += "?Token=$Token$"; } return "http://www.passport.com/gettoken.aspx?BackURL=" + Server.UrlEncode(url); } /// <summary> /// 去掉URL中的令牌 /// 在当前URL中去掉令牌参数 /// </summary> /// <returns></returns> private string replaceToken() { string url = Request.Url.AbsoluteUri; url = Regex.Replace(url, @"(\?|&)Token=.*", "", RegexOptions.IgnoreCase); return "http://www.passport.com/userlogin.aspx?BackURL=" + Server.UrlEncode(url); } } }

浙公网安备 33010602011771号