分布式系统用户统一认证浅析(一)--认证中心被动认证实现
现在越来越多的系统迫于压力以及提高性能,很多站点都是采用多站点分布式运行,例如腾讯、新浪的站点就分成很多个频道,各个频道有独立的域名,独立的IP来支撑,这样一来各个站点之间就出现了统一认证的问题,也就是需要用户在一个站点登录,其他站点都能用的,且退出之后,各个站点都不能用,形成对用户的统一管理,避免了各个子系统之间的功能冗余。
本文就作者自己的一些使用过的设计方法进行整理。使用过的方式主要两种,一是认证中心被动认证,二是认证中心主动认证,本文将介绍被动认证模式。
一、认证流程
主要的流程是,用户第一次访问系统A的页面a,当前系统(系统A)状态还没有登录,所以只能跳转到认证中心进行登录,登录之后,认证中心跳转回来站点A的页面a,该用户现在已经拥有了Token(Token由认证中心根据用户名以及登录时间生成,这个是唯一的字符串,每次生成都会不同),但是站点A不知道此Token是否合法,所以系统A自动跳转到认证中心,拿该Token进行验证,验证通过再跳转回来站点A,此时站点知道用户的Token合法,允许访问页面a。此种验证方法有个小问题就是,访问站点A的每个页面都需要到认证中心认证所拥有的Token是否合法(因为有可能用户会在其中一个子系统退出,退出后用户的旧Token为非法Token)
二、认证实现(C#,VS2008)
首先,建立认证中心的Web站点,页面机构如下:
子站点SubWebSite工程,页面结构如下:
修改一下上边的验证示意图,得到页面调用顺序示意图:
来看实现代码:
SubWebSite:Default.aspx
<form id="form1" runat="server">
<div>
通过了认证,登录的用户名为<%=Session["UserName"] %>
<asp:Button ID="btnSignOut" runat="server" Text="退出"
onclick="btnSignOut_Click" />
</div>
</form>
Default.aspx.cs:
protected void Page_Load(object sender, EventArgs e)
{
//当前子系统登录,且没有从认证中心取得Token
if (Session["Token"] == null && Request.QueryString["Token"] == null)
ReSignIn();//需要重新登录
//Session和Url中都有Token
if (Request.QueryString["Token"] != null && Session["Token"] != null)
{
//Url中的Token和Session中的Token不一致,Token已经失效
string urlToken = Request.QueryString["Token"];
string sessionToken = Request.QueryString["Token"];
if (!urlToken.Equals(sessionToken))
{
ReSignIn();//需要重新登录
}
else
{
string userName = Request["UserName"];
//在本地系统登录
if (SignInSubSys(userName))
{
Session["Token"] = string.Empty;
Response.End();//登录失败
}
}
}
//已经从认证中心取得Token,根据Token取认证中心取得用户信息
else if (Request.QueryString["Token"] != null && Session["Token"] == null)
{
Session["Token"] = Request.QueryString["Token"];
Response.Redirect("Http://mowen:8000/UserCenter/GetUserInfo.aspx?ReturnUrl=" +
HttpUtility.UrlEncode(Request.Url.AbsoluteUri) + "&Token=" + Request.QueryString["Token"]);
}
else
{
ReSignIn();
}
}
/// <summary>
/// 重新登录获取Token
/// </summary>
protected void ReSignIn()
{
Response.Redirect("http://mowen:8000/UserCenter/Default.aspx?ReturnUrl=" + HttpUtility.UrlEncode(Request.Url.AbsoluteUri));
}
/// <summary>
/// 在子站点进行登录
/// </summary>
/// <returns></returns>
protected bool SignInSubSys(string userName)
{
if (!string.IsNullOrEmpty(userName))
{
Session["UserName"] = userName;
}
return false;
}
/// <summary>
/// 退出登录
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void btnSignOut_Click(object sender, EventArgs e)
{
//清空Session
Session.Clear();
//跳转到认证中心
Response.Redirect("Http://mowen:8000/UserCenter/SignOut.aspx?ReturnUrl=" +
HttpUtility.UrlEncode(Request.Url.AbsoluteUri));
}
认证中心获取Token页面(Default.aspx.cs):
protected void Page_Load(object sender, EventArgs e)
{
//来源的Url(此Http请求上一个请求,由上一个请求使用参数传递)
var returnUrl = string.Empty;
if (Request["ReturnUrl"] != null)
returnUrl = HttpUtility.HtmlDecode(Request["ReturnUrl"].Trim());
//根据Session来判断用户是否已经登录
if(Session["UserName"] != null && Session["Token"] != null)
{
//附加上Token参数并告诉子系统当前登录的用户名
if (returnUrl.IndexOf("?") > 0)
returnUrl = returnUrl + "&Token=" + Session["Token"] + "&UserName=" + Session["UserName"];
else
returnUrl = returnUrl + "?Token=" + Session["Token"] + "&UserName=" + Session["UserName"];
//已经登录
//跳转到原地址并加上Token
Response.Redirect(returnUrl);
}
else
{
//没有登录,跳转到登录页面
Response.Redirect("SignIn.aspx?ReturnUrl=" + HttpUtility.UrlEncode(returnUrl));
}
}
认证中心登录页面:
SignIn.aspx:
<form id="form1" runat="server">
<div>
用户名:<asp:TextBox ID="txtUserName" runat="server"></asp:TextBox><br />
密码:<asp:TextBox ID="txtPwd" runat="server"></asp:TextBox><br />
<asp:Button ID="btnSignIn" runat="server" Text="登录" onclick="btnSignIn_Click" />
</div>
</form>
SignIn.aspx.cs:
protected void btnSignIn_Click(object sender, EventArgs e)
{
Session["UserName"] = txtUserName.Text.Trim();
Session["Token"] =
System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(
txtUserName.Text.Trim() + DateTime.Now, "md5");
//*************************************************************************
//将Token和用户信息关联起来
Hashtable htTokenInfo = null;
if (Application["UserTokenInfo"] != null)
htTokenInfo = (Hashtable)Application["UserTokenInfo"];
if (htTokenInfo == null)
htTokenInfo = new Hashtable();
if (!htTokenInfo.ContainsKey(Session["Token"]))
htTokenInfo.Add(Session["Token"], txtUserName.Text.Trim());
else
htTokenInfo[Session["Token"]] = txtUserName.Text.Trim();
Application["UserTokenInfo"] = htTokenInfo;
//*************************************************************************
//来源的Url(此Http请求上一个请求,由上一个请求使用参数传递)
var returnUrl = string.Empty;
if (Request["ReturnUrl"] != null)
returnUrl = HttpUtility.HtmlDecode(Request["ReturnUrl"].Trim());
returnUrl = BuildUrl(returnUrl, "Token", Session["Token"].ToString());
//跳转回去源地址
Response.Redirect(returnUrl);
}
/// <summary>
/// 功能:url里有key的值,就替换为value,没有的话就追加.
/// 执行过程:(1)、使用正则表达式匹配key
/// (2)、将匹配的Key的值替换为空的值
/// (3)、使用新值进行替换
/// 作者:莫文
/// 时间:2010-5-30 13:48
/// Email:mowen@founder.com
///
/// </summary>
/// <param name="url">要替换Url参数值的Url</param>
/// <param name="paramText">要替换值的参数名</param>
/// <param name="paramValue">要被替换的参数的值</param>
/// <returns>替换参数值后的Url</returns>
public static string BuildUrl(string url, string paramText, string paramValue)
{
//使用正则匹配所要查找的Key
Regex reg = new Regex(string.Format("{0}=[^&]*", paramText), RegexOptions.IgnoreCase);
Regex reg1 = new Regex("[&]{2,}", RegexOptions.IgnoreCase);
//将旧值替换为空
string _url = reg.Replace(url, "");
//新值
if (_url.IndexOf("?") == -1)
_url += string.Format("?{0}={1}", paramText, paramValue);//?
else
_url += string.Format("&{0}={1}", paramText, paramValue);//&
//将新值替换到Url中
_url = reg1.Replace(_url, "&");
//将多余的&字符清除
_url = _url.Replace("?&", "?");
return _url;
}
认证中心验证Token验证页面(GetUserInfo.aspx.cs):
protected void Page_Load(object sender, EventArgs e)
{
Hashtable htTokenInfo = null;
if (Application["UserTokenInfo"] != null)
htTokenInfo = (Hashtable)Application["UserTokenInfo"];
//来源的Url(此Http请求上一个请求,由上一个请求使用参数传递)
var returnUrl = string.Empty;
if (Request["ReturnUrl"] != null)
returnUrl = HttpUtility.HtmlDecode(Request["ReturnUrl"].Trim());
string token = Request["Token"];
if (htTokenInfo == null || string.IsNullOrEmpty(token))
{
//没有登录,跳转到登录页面
Response.Redirect("SignIn.aspx?ReturnUrl=" + HttpUtility.UrlEncode(returnUrl));
}
else
{
//用户信息是否和Session关联
if (htTokenInfo[token] == null)
//没有登录,跳转到登录页面
Response.Redirect("SignIn.aspx?ReturnUrl=" + HttpUtility.UrlEncode(returnUrl));
//附加上Token参数
if (returnUrl.IndexOf("?") > 0)
returnUrl = returnUrl + "&UserName=" + htTokenInfo[token];
else
returnUrl = returnUrl + "?UserName=" + htTokenInfo[token];
//跳回原页面
Response.Redirect(returnUrl);
}
}
认证中心验证退出页面(SignOut.aspx.cs):
protected void Page_Load(object sender, EventArgs e)
{
//清空Session
Session.Clear();
var returnUrl = string.Empty;
if (Request["ReturnUrl"] != null)
returnUrl = HttpUtility.HtmlDecode(Request["ReturnUrl"].Trim());
//跳转到登录页面
Response.Redirect("SignIn.aspx?ReturnUrl=" + HttpUtility.UrlEncode(returnUrl));
}
代码下载:http://www.cnfounder.com/mw/UserCenterDemo.rar
欢迎转载,请注明出处。谢谢。
分布式系统用户统一认证浅析(一)--认证中心被动认证实现相关推荐
- 分布式系统用户统一认证浅析(二)认证中心主动认证实现
上一篇文章写了被动认证的实现,本文接着写主动认证的实现. 一.认证流程 为了和被动认证有个比较,这些列出被动认证的流程图 1.1认证(图1为被动认证,图2为主动认证): 主动认证的流程和被动的区别是, ...
- @ZBBIX集成LDAP功能实现用户统一登录认证
文章目录 1.zabbix认证方式 2.LDAP模块查看 3.windows AD配置 4.zabbix配置LDAP 5.开启LDAP账户登录 6.AD账户登录测试 7.AD账户批量添加zabbix ...
- ur机械臂 控制器_OnRobot末端执行器和统一接口已通过UR +计划认证
近日,OnRobot 宣布其One System Solution末端执行器和统一接口现已通过UR +计划认证,UR +计划对夹具等配件进行测试和认证,以便与Universal Robots A / ...
- Zabbix 对接 LDAP 实现用户统一登录的方法
需求 某公司环境是基于AD域来批量管理域用户的,zabbix监控平台上又要创建账号,这样非常麻烦,也不利于账号的管理,所以为了集中管理,想通过zabbix对接公司AD域用户,实现用户认证统一登录. 环 ...
- SpringBoot实现用户统一管理与单点登陆
前言 最近在开发产品的过程中,需要将业务功能拆分成独立子系统,既可以单独使用也可以集成部署,这里就需要对框架进行扩展,支持用户统一管理与单点登陆.我们的基础框架使用redis实现token认证,所以只 ...
- 浅析 Spring Security 的认证过程及相关过滤器
前言 上一篇文章 浅析 Spring Security 核心组件 中介绍了Spring Security的基本组件,有了前面的基础,这篇文章就来详细分析下Spring Security的认证过程. S ...
- 华为外部Portal认证 Radius认证计费 实现基于Mac快速认证的Mac无感知认证和结合CAS单点登录统一认证平台和AD域LDAP对接配置
华为外部Portal认证 Radius认证计费 实现基于Mac快速认证的Mac无感知认证 结合CAS单点登录统一认证平台 AD域LDAP对接配置 实现用户名密码实名认证 访客短信认证 二维码扫码 钉钉 ...
- 用户统一密码管理校验服务说明
1 背景说明 目前大多数企业尤其是集团性企业已经构建了一定的信息化系统,但伴随信息系统越建越多,账户体系紊乱.用户不统一.体系不统一的弊端越来越明显.当前企业亟需解决全集团内部的"统一认证& ...
- 配置用户通过Telnet登录设备的身份认证(AAA本地认证)
背景信息 用户通过Telnet登录设备时,设备上必须配置验证方式,否则用户无法成功登录设备.设备支持不认证.密码认证和AAA认证三种用户界面的验证方式,其中AAA认证方式安全性最高. 采用AAA本地认 ...
最新文章
- 只知道用它打印了Hello World,除此之外你了解多少呢?
- 利用 Android Studio 和 Gradle 打包多版本APK
- Jupyter notebook 运行环境创建和切换 (Win10+Anaconda)
- 18、Page Object 设计模式
- PS制作立体效果——圆柱
- 【桶】220.存在重复元素 III 【LeetCode】
- css3动画animation,transition
- tf.nn.dropout
- 洛谷P2312解方程题解
- linux socket通信编程之c语言(客户端和服务器程序)
- Nginx常用命令介绍
- YQMKPAT(CAD图案填充插件)v2.1绿色版
- 【信号与系统】笔记合集,你确定不收藏吗?我已经收藏了
- 超定方程组最小二乘matlab,超定方程组最优解(最小二乘解)推导
- win32 指令大全
- 不浪漫爱情--等你来--等你来
- SparkSql之电影案例SQL编写
- ups不间断电源品牌_德国阳光蓄电池_蓄电池代理-山东万仁电源设备有限公司
- Adapter适配器
- 家用智能洗地机哪个牌子好、这几款旗舰机好用又实惠