.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.设置 ...
随机推荐
- FFmpeg学习3:播放音频
参考dranger tutorial,本文将介绍如何使用FFmpeg解码音频数据,并使用SDL将解码后的数据输出. 本文主要包含以下几方面的内容: 关于播放音频的需要的一些基础知识介绍 使用SDL2播 ...
- 微信JS-SDK坐标位置转换为百度地图坐标
微信JS-SDK开发过程中,使用getLocation获取坐标位置,如何将微信获取的坐标直接应用到百度地图中,显示以下效果: 说明:红色图标是从微信转换过来的位置,蓝色图标是周边位置.首先从微信开发流 ...
- 微信js框架第二篇(创建完整界面布局)
接着昨天的继续谈关于微信新出的这个js框架,今天主要谈一个页面的创建到布局的详细步骤. 一.创建一个完整页面 页面你可以创建在项目的任何节点,只要你在入口文件正确引入创建该页面的路径就可使 ...
- 5分钟创建一个SpringBoot + Themeleaf的HelloWord应用
第一步:用IDE创建一个普通maven工程,我用的eclipse. 第二步:修改pom.xml,加入支持SpringBoot和Themeleaf的依赖,文件内容如下: <?xml version ...
- canvas调用scale或者drawImage图片操作后,锯齿感很明显的解决
<script type="text/javascript"> //解决canvas画画图片 var mengvalue = -1; var phoneWidth = ...
- Java-加载数据库驱动,取得数据库连接
在Java中想要进行数据库操作,最重要的两个步骤就是加载数据驱动,然后取得数据库连接. 1.加载 数据库驱动( Class.forName(String className) ): 因为Java是一种 ...
- Windows Server2008 下用于.NET Framework3.0版本的问题无法在IIS7中配置.NET Framework4.0节点的问题
Windows Server 2008中,功能列表安装的为.NET Framework3.0. 试了N种方法未升级为.NET Framework4.0(哪位如果可以直接升级为4.0或3.5希望能够分享 ...
- Android关于listView的BaseAdapter以及getView的三级优化
1.4个重写方法的含义 自定义Adapter继承自BaseAdapter(通用适配器) getCount(); getItem(); getItemId(); getViewTypaCount() ...
- 【代码笔记】iOS-获得现在的日期
一,代码. - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, ...
- PHPmailer关于Extension missing: openssl报错的解决
最近在写一个网页的时候,需要用到PHPmailer来发送邮件,按照官网上给出的demo写出一个例子,却报错Extension missing: openssl 最后发现需要修改php.ini中的配置: ...