后端开发|C#.Net教程
,设计,登录
后端开发-C#.Net教程
本篇文章主要介绍了 MVC SSO单点登录设计与实现,具有一定的参考价值,有兴趣的可以了解一下。
澳门新葡京源码下载,ubuntu开机开不开,tomcat404怎么处理,爬虫 假页面,php代码占用cpu过高,丝瓜seolzw
实验环境配置
vc6 串口通信源码下载,ubuntu mpi运行,启动tomcat 地址栏,肯德基餐厅爬虫,php视频加密,天津短视频seo怎么精准获客lzw
HOST文件配置如下:
114系统源码,ubuntu的vi编辑,日志服务器 tomcat,爬虫代码搜索,php批量查询域名注册,seo 友好lzw
127.0.0.1
127.0.0.1
IIS配置如下:
应用程序池采用.Net Framework 4.0
注意IIS绑定的域名,两个完全不同域的域名。
网站配置如下:
网站配置如下:
memcached缓存:
数据库配置:
数据库采用EntityFramework 6.0.0,首次运行会自动创建相应的数据库和表结构。
授权验证过程演示:
在浏览器地址栏中访问:,如果用户还未登陆则网站会自动重定向至:/passport,同时通过QueryString传参数的方式将对应的AppKey应用标识传递过来,运行截图如下:
URL地址:/passport?appkey=670b14728ad9902aecba32e22fa4f6bd&username=
输入正确的登陆账号和密码后,点击登陆按钮系统自动301重定向至应用会掉首页,毁掉成功后如下所示:
由于在不同的域下进行SSO授权登陆,所以采用QueryString方式返回授权标识。同域网站下可采用Cookie方式。由于301重定向请求是由浏览器发送的,所以在如果授权标识放入Handers中的话,浏览器重定向的时候会丢失。重定向成功后,程序自动将授权标识写入到Cookie中,点击其他页面地址时,URL地址栏中将不再会看到授权标示信息。Cookie设置如下:
登陆成功后的后续授权验证(访问其他需要授权访问的页面):
校验地址:/api/passport?sessionkey=xxxxxx&remark=xxxxxx
返回结果:true,false
客户端可以根据实际业务情况,选择提示用户授权已丢失,需要重新获得授权。默认自动重定向至SSO登陆页面,即:/passport?appkey=670b14728ad9902aecba32e22fa4f6bd&username=seo@ 同时登陆页面邮箱地址文本框会自定补全用户的登陆账号,用户只需输入登陆密码即可,授权成功后会话有效期自动延长一年时间。
SSO数据库验证日志:
用户授权验证日志:
用户授权会话Session:
数据库用户账号和应用信息:
应用授权登陆验证页面核心代码:
/// public class PassportController : Controller { private readonly IAppInfoService _appInfoService = new AppInfoService(); private readonly IAppUserService _appUserService = new AppUserService(); private readonly IUserAuthSessionService _authSessionService = new UserAuthSessionService(); private readonly IUserAuthOperateService _userAuthOperateService = new UserAuthOperateService(); private const string AppInfo = "AppInfo"; private const string SessionKey = "SessionKey"; private const string SessionUserName = "SessionUserName"; //默认登录界面 public ActionResult Index(string appKey = "", string username = "") {TempData[AppInfo] = _appInfoService.Get(appKey);var viewModel = new PassportLoginRequest{ AppKey = appKey, UserName = username};return View(viewModel); } //授权登录 [HttpPost] public ActionResult Index(PassportLoginRequest model) {//获取应用信息var appInfo = _appInfoService.Get(model.AppKey);if (appInfo == null){ //应用不存在 return View(model);}TempData[AppInfo] = appInfo;if (ModelState.IsValid == false){ //实体验证失败 return View(model);}//过滤字段无效字符model.Trim();//获取用户信息var userInfo = _appUserService.Get(model.UserName);if (userInfo == null){ //用户不存在 return View(model);}if (userInfo.UserPwd != model.Password.ToMd5()){ //密码不正确 return View(model);}//获取当前未到期的Sessionvar currentSession = _authSessionService.ExistsByValid(appInfo.AppKey, userInfo.UserName);if (currentSession == null){ //构建Session currentSession = new UserAuthSession {AppKey = appInfo.AppKey,CreateTime = DateTime.Now,InvalidTime = DateTime.Now.AddYears(1),IpAddress = Request.UserHostAddress,SessionKey = Guid.NewGuid().ToString().ToMd5(),UserName = userInfo.UserName }; //创建Session _authSessionService.Create(currentSession);}else{ //延长有效期,默认一年 _authSessionService.ExtendValid(currentSession.SessionKey);}//记录用户授权日志_userAuthOperateService.Create(new UserAuthOperate{ CreateTime = DateTime.Now, IpAddress = Request.UserHostAddress, Remark = string.Format("{0} 登录 {1} 授权成功", currentSession.UserName, appInfo.Title), SessionKey = currentSession.SessionKey}); 104 var redirectUrl = string.Format("{0}?SessionKey={1}&SessionUserName={2}", appInfo.ReturnUrl, currentSession.SessionKey, userInfo.UserName);//跳转默认回调页面return Redirect(redirectUrl); } }Memcached会话标识验证核心代码:public class PassportController : ApiController { private readonly IUserAuthSessionService _authSessionService = new UserAuthSessionService(); private readonly IUserAuthOperateService _userAuthOperateService = new UserAuthOperateService(); public bool Get(string sessionKey = "", string remark = "") {if (_authSessionService.GetCache(sessionKey)){ _userAuthOperateService.Create(new UserAuthOperate {CreateTime = DateTime.Now,IpAddress = Request.RequestUri.Host,Remark = string.Format("验证成功-{0}", remark),SessionKey = sessionKey }); return true;}_userAuthOperateService.Create(new UserAuthOperate{ CreateTime = DateTime.Now, IpAddress = Request.RequestUri.Host, Remark = string.Format("验证失败-{0}", remark), SessionKey = sessionKey});return false; } }
Client授权验证Filters Attribute
public class SSOAuthAttribute : ActionFilterAttribute { public const string SessionKey = "SessionKey"; public const string SessionUserName = "SessionUserName"; public override void OnActionExecuting(ActionExecutingContext filterContext) {var cookieSessionkey = "";var cookieSessionUserName = "";//SessionKey by QueryStringif (filterContext.HttpContext.Request.QueryString[SessionKey] != null){ cookieSessionkey = filterContext.HttpContext.Request.QueryString[SessionKey]; filterContext.HttpContext.Response.Cookies.Add(new HttpCookie(SessionKey, cookieSessionkey));}//SessionUserName by QueryStringif (filterContext.HttpContext.Request.QueryString[SessionUserName] != null){ cookieSessionUserName = filterContext.HttpContext.Request.QueryString[SessionUserName]; filterContext.HttpContext.Response.Cookies.Add(new HttpCookie(SessionUserName, cookieSessionUserName));}//从Cookie读取SessionKeyif (filterContext.HttpContext.Request.Cookies[SessionKey] != null){ cookieSessionkey = filterContext.HttpContext.Request.Cookies[SessionKey].Value;}//从Cookie读取SessionUserNameif (filterContext.HttpContext.Request.Cookies[SessionUserName] != null){ cookieSessionUserName = filterContext.HttpContext.Request.Cookies[SessionUserName].Value;}if (string.IsNullOrEmpty(cookieSessionkey) || string.IsNullOrEmpty(cookieSessionUserName)){ //直接登录 filterContext.Result = SsoLoginResult(cookieSessionUserName);}else{ //验证 if (CheckLogin(cookieSessionkey, filterContext.HttpContext.Request.RawUrl) == false) {//会话丢失,跳转到登录页面filterContext.Result = SsoLoginResult(cookieSessionUserName); }}base.OnActionExecuting(filterContext); } public static bool CheckLogin(string sessionKey, string remark = "") {var httpClient = new HttpClient{ BaseAddress = new Uri(ConfigurationManager.AppSettings["SSOPassport"])};var requestUri = string.Format("api/Passport?sessionKey={0}&remark={1}", sessionKey, remark);try{ var resp = httpClient.GetAsync(requestUri).Result; resp.EnsureSuccessStatusCode(); return resp.Content.ReadAsAsync().Result;}catch (Exception ex){ throw ex;} } private static ActionResult SsoLoginResult(string username) {return new RedirectResult(string.Format("{0}/passport?appkey={1}&username={2}",ConfigurationManager.AppSettings["SSOPassport"],ConfigurationManager.AppSettings["SSOAppKey"],username)); } }
示例SSO验证特性使用方法:
[SSOAuth] public class HomeController : Controller { public ActionResult Index() {return View(); } public ActionResult About() {ViewBag.Message = "Your application description page.";return View(); } public ActionResult Contact() {ViewBag.Message = "Your contact page.";return View(); } }
总结:
从草稿示例代码中可以看到代码性能上还有很多优化的地方,还有SSO应用授权登陆页面的用户账号不存在、密码错误等一系列的提示信息等。在业务代码运行基本正确的后期,可以考虑往更多的安全性层面优化,比如启用AppSecret私钥签名验证,IP范围验证,固定会话请求攻击、SSO授权登陆界面的验证码、会话缓存自动重建、SSo服务器、缓存的水平扩展等。