.net 单点登录实践
前言
最近轮到我在小组晨会来分享知识点,突然想到单点登录,准备来分享下如何实现单点登录,所以有了下文。实现方案以及代码可能写得不是很严谨,有漏洞的地方或者错误的地方欢迎大家指正。
刚开始头脑中没有思路,直接在博客园里面看看别人是如何来实现的,看了几篇文章发现,发现解决方案有点问题,或者说不算实现了单点登录
名称定义
为了方便说明先说明几个文中出现的名词的含义:
P站:统一登录授权验证中心,demo中 域名是www.passport.com:801
A站:处于不同域名下的测试网站,demo中 域名是www.a.com:802
B站:处于不同域名下的测试网站,demo中 域名是www.b.com:803
单点登录
访问A站需要登陆的就跳转P站中进行登陆,P站登陆之后跳转回至A站,用户再次访问B站需要登陆的页面,用户不需要进行登陆操作就可以正常访问。
实现思路
简单关系图

泳道流程图

主要逻辑说明
A站主要逻辑
/// <summary>
/// 生成秘钥
/// </summary>
/// <param name="timestamp"></param>
/// <returns></returns>
public static string CreateToken(DateTime timestamp)
{
StringBuilder securityKey = new StringBuilder(MD5Encypt(timestamp.ToString("yyyy")));
securityKey.Append(MD5Encypt(timestamp.ToString("MM")));
securityKey.Append(MD5Encypt(timestamp.ToString("dd")));
securityKey.Append(MD5Encypt(timestamp.ToString("HH")));
securityKey.Append(MD5Encypt(timestamp.ToString("mm")));
securityKey.Append(MD5Encypt(timestamp.ToString("ss")));
return MD5Encypt(securityKey.ToString());
}
P回调A的时候进行,A中对Token进行校验,校验不成功则请求P站统一授权验证。
/// <summary>
/// 授权枚举
/// </summary>
public enum AuthCodeEnum
{
Public = ,
Login =
} /// <summary>
/// 授权过滤器
/// </summary>
public class AuthAttribute : ActionFilterAttribute
{
/// <summary>
/// 权限代码
/// </summary>
public AuthCodeEnum Code { get; set; } /// <summary>
/// 验证权限
/// </summary>
/// <param name="filterContext"></param>
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var request = filterContext.HttpContext.Request;
var session = filterContext.HttpContext.Session;
//如果存在身份信息
if (Common.CurrentUser == null)
{
if (Code == AuthCodeEnum.Public)
{
return;
}
string reqToken = request["Token"];
string ticket = request["Ticket"];
Cache cache = HttpContext.Current.Cache;
//没有获取到Token或者Token验证不通过或者没有取到从P回调的ticket 都进行再次请求P
TokenModel tokenModel= cache.Get(ConstantHelper.TOKEN_KEY)==null?null:(TokenModel)cache.Get(ConstantHelper.TOKEN_KEY);
if (string.IsNullOrEmpty(reqToken) || tokenModel == null || tokenModel.Token!= reqToken ||
string.IsNullOrEmpty(ticket))
{
DateTime timestamp = DateTime.Now;
string returnUrl = request.Url.AbsoluteUri;
tokenModel = new TokenModel
{
TimeStamp = timestamp,
Token = AuthernUtil.CreateToken(timestamp)
};
//Token加入缓存中,设计过期时间为20分钟
cache.Add(ConstantHelper.TOKEN_KEY, tokenModel, null, DateTime.Now.AddMinutes(),Cache.NoSlidingExpiration,CacheItemPriority.Default, null);
filterContext.Result = new ContentResult
{
Content = GetAuthernScript(AuthernUtil.GetAutherUrl(tokenModel.Token, timestamp), returnUrl)
};
return;
}
LoginService service = new LoginService();
var userinfo = service.GetUserInfo(ticket);
session[ConstantHelper.USER_SESSION_KEY] = userinfo;
//验证通过,cache中去掉Token,保证每个token只能使用一次
cache.Remove(ConstantHelper.TOKEN_KEY);
}
} /// <summary>
/// 生成跳转脚本
/// </summary>
/// <param name="authernUrl">统一授权地址</param>
/// <param name="returnUrl">回调地址</param>
/// <returns></returns>
private string GetAuthernScript(string authernUrl, string returnUrl)
{
StringBuilder sbScript = new StringBuilder();
sbScript.Append("<script type='text/javascript'>");
sbScript.AppendFormat("window.location.href='{0}&returnUrl=' + encodeURIComponent('{1}');", authernUrl, returnUrl);
sbScript.Append("</script>");
return sbScript.ToString();
}
}
代码说明:这里为了方便设置Token的过期时间,所以使用Cache来存取Token,设定Token的失效时间为两分钟,当验证成功则从cache中移除Token。
调取过滤器
[Auth(Code = AuthCodeEnum.Login)]
public ActionResult Index()
{
return View();
}
P站主要逻辑
P站收到授权请求,P站首先通过Coookie来判断是否登陆,未登录则跳转至登陆页面进行登陆操作。
/// <summary>
/// 授权登陆验证
/// </summary>
/// <returns></returns>
[HttpPost]
public ActionResult PassportVertify()
{
var cookie=Request.Cookies[ConstantHelper.USER_COOKIE_KEY];
if (cookie == null ||string.IsNullOrEmpty(cookie.ToString()))
{
return RedirectToAction("Login", new { ReturnUrl = Request["ReturnUrl"] ,Token= Request["Token"] });
}
string userinfo = cookie.ToString();
var success= passportservice.AuthernVertify(Request["Token"], Convert.ToDateTime(Request["TimeStamp"]));
if (!success)
{
return RedirectToAction("Login", new { ReturnUrl = Request["ReturnUrl"], Token = Request["Token"] });
}
return Redirect(passportservice.GetReturnUrl(userinfo, Request["Token"],Request["ReturnUrl"]));
}
已登陆则验证Token
/// <summary>
/// 验证令牌
/// </summary>
/// <param name="token">令牌</param>
/// <param name="timestamp">时间戳</param>
/// <returns></returns>
public bool AuthernVertify(string token,DateTime timestamp)
{
return AuthernUtil.CreateToken(timestamp) == token;
}
测试说明
1、修改host
127.0.0.1 www.passport.com
127.0.0.1 www.a.com
127.0.0.1 www.b.com
2、部署IIS
P www.passport.com:801
A www.a.com:802
B www.b.com:803
3、测试账号和webconfig
<add key="PassportCenterUrl" value="http://www.passport.com:801"/>
用户名:admin 密码:123
demo
https://github.com/hexuefengx/study
.net 单点登录实践的更多相关文章
- CAS单点登录实践(spring cas client配置)
前言: 最近的项目需要将多个站点统一登录,查阅了资料Jasig cas(Central Authentication Service)(官方站点:http://www.jasig.org/cas)使用 ...
- Windows Azure 安全最佳实践 - 第 5 部分:基于Claim 的标识,单点登录
基于Claim的身份标识是处理网站与 Web 服务的身份认证和访问一种简单而强大的方式,无论您是在本地工作还是面向云工作.您可以通过减少自定义实施和使用基于Claim的单一简化标识模型,创建更安全的应 ...
- 移动App如何实践单点登录
移动应用实现单点登录,分析下面两种需求: 需求一: 账号在正在设备A上使用(应用是设备A上当前活动应用), 若设备B上用该账号登录应用,要求设备A上的账号立即退出. 解决办法: 应用客户端上做个定时 ...
- SSO单点登录系列3:cas-server端配置认证方式实践(数据源+自定义java类认证)
落雨 cas 单点登录 本篇将讲解cas-server端的认证方式 1.最简单的认证,用户名和密码一致就登录成功 2.配置Oracle的jdbc数据源,通过spring动态查询数据库 3.配置orac ...
- 著名ERP厂商的SSO单点登录解决方案介绍一
SSO英文全称Single Sign On,单点登录.SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统.它包括可以将这次主要的登录映射到其他应用中用于同一个用户 ...
- [原创]django+ldap+memcache实现单点登录+统一认证
前言 由于公司内部的系统越来越多,为了方便用户使用,通过django进行了单点登录和统一认证的尝试,目前实现了django项目的单点登录和非django项目的统一认证,中间波折挺多,涉及的技术包括dj ...
- 使用Crowd2.7集成Confluence5.3与JIRA6.1,并安装、破解及汉化,实现单点登录【原创】
鉴于目前没有针对Crowd.Confluence.Jira安装.集成和破解最新的方法,总结今天安装.破解及集成的经验,编写此文,方便大家进行配置也方便自己以后参考.此文参考多篇破解文章,并经过作者 ...
- java web SSO单点登录
第一篇: Web应用系统的演化总是从简单到复杂,从单功能到多功能模块再到多子系统方向发展. .当前的大中型Web互联网应用基本都是多系统组成的应用群,由多个web系统协同为用户提供服务. 多系统应用群 ...
- SSO 基于Cookie+fliter实现单点登录 实例解析(一)
接上文,SSO的理论讲解,接下来实践实践! 1.使用Cookie解决单点登录 技术点: 1.设置Cookie的路径为setPath("/").即Tomcat的目录下都有效 2.设置 ...
随机推荐
- Signalr系列之虚拟目录详解与应用中的CDN加速实战
目录 对SignalR不了解的人可以直接移步下面的目录 SignalR系列目录 前言 前段时间一直有人问我 在用SignalR 2.0开发客服系统[系列1:实现群发通讯]这篇文章中的"/Si ...
- jQuery操作DOM元素
作为一个后端程序员,也是要和前端页面打交道的.最常见的场景莫过DOM元素操作和前端页面使用AJAX向服务器发送请求.实现上述两个功能当然可以使用原生js来完成,但在实际开发过程中很少这样做,通常会使用 ...
- [C1] 实现 C1FlexGrid 撤销还原功能
采用设计模式中的"命令模式"实现 C1FlexGrid 的撤销还原功能,那就先从命令模式简单介绍开始吧. 一 命令模式 命令模式属于对象的行为型模式,将一个请求封装为一个对象,从 ...
- SIMLock锁卡功能解析
一.锁卡背景介绍 锁卡即SIMLock,当手机开机启动或者插入SIM卡时,手机modem侧预置在NV项中的配置信息会与SIM卡中的信息做比对,检测是否匹配.若匹配,则SIM卡可以正常使用.若不匹配,则 ...
- 【重大更新】开源跨平台物联网通讯框架ServerSuperIO 2.0(SSIO)下载
更新具体细节参见:[更新设计]跨平台物联网通讯框架ServerSuperIO 2.0 ,功能.BUG.细节说明,以及升级思考过程! 声明:公司在建设工业大数据平台,SSIO正好能派上用场,所以抓紧时间 ...
- ArcGIS Engine开发前基础知识(3)
对象模型图 一.对象模型图中的类与接口 ArcGIS Engine 提供大量的对象,这些对象之间存在各种各样的关系,如继承.组合.关联等.对象模型图(Object model diagram,ODM) ...
- ASP.NET MVC 5 01 - ASP.NET概述
本篇目录: ASP.NET 概述 .NET Framework 与 ASP.NET ASP.NET MVC简介 ASP.NET的特色和优势 典型案例 ▁▃▅ ASP.NET概述 ▅▃▁ 目前开发B/S ...
- 排序 order by 的用法
order by 跟在select* from 后面 order by 默认的是升序, asc 升序 desc 降序 select * from 表名 order by 字段名 asc 在带有 ...
- 在Windows中玩转Docker Toolbox
最近在研究虚拟化,容器和大数据,所以从Docker入手,下面介绍一下在Windows下怎么玩转Docker. Docker本身在Windows下有两个软件,一个就是Docker,另一个是Docker ...
- OutPut子句的使用限制
Output子句很方便,多数情况下可以省略了更新后插入或者删除后插入操作表,将2个语句变成1个语句操作.不管从语句美观还是效率上都是有不错的提升, 但是对于Output自身,也是有一些限制的. 从文档 ...