asp.net MVC 中 单点登录 傷城~ 2022-10-26 12:51 110阅读 0赞 实现sso系统的主要难点: 1:不能直接访问数据库,有安全隐患,而且还容易乱套。 2:多个系统需要进行单点登录,逻辑需要严谨,能支持N多系统、而不只是少数几个系统。 3:代码不能过于复杂,需要简洁,灵活支持本地部署,单点部署,集群部署,相同的代码可以通过部署配置灵活实现服务段(sso)、本地段(子网站)功能。 4:多系统的权限也可以灵活判断,不能访问数据库,需要进行远程服务调用,而且还需要对外部系统能提供调用接口。 5:需要有一定的安全性,能防止注入攻击等等。 6:权限定义需要非常灵活,可以定义10个权限,也可以定义100个权限,可以根据url进行权限判断,同时可以是n多个业务系统。 1、流程: a) **用户直接访问门户url,登录成功后跳转到默认应用的url**。 程序里需要引用2个Dll,通用权限管理系统组件的,这2个dll主要实现权限判断,登录功能等。 ![25205715-37877cdd5c6e4f27a6ebc6b5b4f5a687.png][] 下面是登录页面的位置 ![25133720-ceea385b0e694947b90708cc7e1c94a5.png][] 这里是MVC默认的登录页面, ![25134044-e6aee3d1ad8c45d79679cd96700d5e64.png][] 上图是需要登录的功能定义部分。 ![25134125-f2b4f18127be45fca5f32f34629f5d79.png][] 在 MVC 里加上 \[NeedAuthorize\] 就可以默认要求登录了。不登录不允许访问了。 b) **用户直接访问应用url,若未登录,跳转到登录页面的url,完成登录后,跳转回应用url**。 ![25134342-93172a634e89470c84b9ce20c7bfb2a0.png][] 上图是跳转的处理,若没指定需要跳转的页面,那就默认回到首页,若有指定的 returnUrl,就跳转回指定的页面里。 c) **用户已经登录,用户直接访问应用的URL,若该用户无权限,跳转到指定的url** 没有访问权限的用户会被重定向到没权限访问的页面 ![25142704-64ade270fcab48c69010a26bf744da8e.png][] 系统中的注意事项,先看下图 ![25154153-a60700eb2d8f4c6db6645516d4fd0661.png][] NeedUrlAuthorizedAttribute 是需要进行url验证用的属性,在需要控制的Controller上加上,例如 判断是否有url权限的调用方法如下: \[NeedAuthorize\] 需要进行登录(这个可以省略) \[NeedUrlAuthorized\] 需要进行Url验证 (首先会要求需要登录) \[HttpPost\] public ActionResult User(Friend.Models.User model) \{ \} PermissionWebService 是进行权限验证中心远程进行权限判断的WebService,是引用了 [http://www.sso.com/PermissionService.asmx][http_www.sso.com_PermissionService.asmx] 这个WebService。 需要在配置文件里进行 配置 ![25154556-5d5e3a10f65d44f78aca500f99b0d45c.png][] SystemCode, 主要是来识别,是哪个子系统的权限?因为当前可能10多个网站,那就是有10多个子系统,那就每个子系统需要有一个唯一识别的编号。 那如何设置某个子系统的用的url权限?看下图(用户权限配置参考,子系统设置菜单、菜单编号、菜单url设置): ![25200813-4ec50773e46941a2bfcc3e0ed24f3d28.png][] 若没登录,就会提示先登录 ![25205224-74719dcfa881461bbf4bd224ffc2e686.png][] 登录后,若没权限访问这个页面,就会提示没权限访问。 ![25204815-8d9541001b504529a0acb94ff3d7f6b3.png][] 可以点网页下面的 有情连接进行测试,不用在url里人工输入。 ![25204900-f9fdf11ec5ac47ee9271c042f9055b44.png][] d) **用户已经登录,用户直接访问用户有权限的应用url,通过**。 与上面的需求一致,有权限的自然能通过调用。 有URL访问权限的,可以显示页面效果如下 ![25204427-86c85990fa5d458d96c81944c54ec1ce.png][] E) **跨域的单点登录、权限判断需要注意的配置部分**。 ![25134846-066581738b4948b19c113244b19a461a.png][] 需要在其他需要接入的 其他应用里需要加上这3个配置,认证主服务器上不要进行这个配置,需要删除掉这几行配置信息才可以。 2、验证码的生成,封装成一个插件,方便各种加强版本的验证需要。 这个是一个通用的严正码设置与验证码校验的类,可以按自己的需要进行修改。 ![24203719-6ff017c9eb4947a0b9757adb32ac4107.png][] [![复制代码][copycode.gif]][copycode.gif 1] //----------------------------------------------------------------- // All Rights Reserved , Copyright (C) 2013 , Hairihan TECH, Ltd. //----------------------------------------------------------------- using System; using System.Data; using System.Data.Common; using System.Collections.Generic; namespace DotNet.Business { using DotNet.Utilities; /// <summary> /// BaseUserManager /// 用户管理 /// /// 修改纪录 /// /// 2013.08.17 版本:1.0 JiRiGaLa 用户登录后才设置验证码、获取验证码等。 /// /// <author> /// <name>JiRiGaLa</name> /// <date>2011.10.17</date> /// </author> /// </summary> public partial class BaseUserManager : BaseManager { #region public int SetVerificationCode(string userId, string verificationCode) 设置验证码 /// <summary> /// 设置验证码 /// </summary> /// <param name="userId">用户主键</param> /// <param name="verificationCode">验证码</param> /// <returns>影响行数</returns> public int SetVerificationCode(string userId, string verificationCode) { int result = 0; if (string.IsNullOrEmpty(userId) && this.UserInfo != null) { userId = this.UserInfo.Id; } string sqlQuery = string.Empty; sqlQuery = " UPDATE " + BaseUserLogOnEntity.TableName + " SET " + BaseUserLogOnEntity.FieldVerificationCode + " = " + DbHelper.GetParameter("VerificationCode") + " WHERE " + BaseUserLogOnEntity.FieldId + " = " + DbHelper.GetParameter("UserId"); List<IDbDataParameter> dbParameters = new List<IDbDataParameter>(); dbParameters.Add(DbHelper.MakeParameter("VerificationCode", verificationCode)); dbParameters.Add(DbHelper.MakeParameter("UserId", userId)); result = DbHelper.ExecuteNonQuery(sqlQuery, dbParameters.ToArray()); return result; } #endregion #region public bool Verify(string userId, string verificationCode) /// <summary> /// 验证,验证码是否正确 /// </summary> /// <param name="userId">用户主键</param> /// <param name="verificationCode">验证码</param> /// <returns></returns> public bool Verify(string userId, string verificationCode) { bool result = false; string sqlQuery = string.Empty; // 最后一次登录时间 sqlQuery = " SELECT COUNT(1)" + " FROM " + BaseUserLogOnEntity.TableName + " WHERE " + BaseUserLogOnEntity.FieldVerificationCode + " = " + DbHelper.GetParameter("VerificationCode") + " AND " + BaseUserLogOnEntity.FieldId + " = " + DbHelper.GetParameter("UserId"); List<IDbDataParameter> dbParameters = new List<IDbDataParameter>(); dbParameters.Add(DbHelper.MakeParameter("VerificationCode", verificationCode)); dbParameters.Add(DbHelper.MakeParameter("UserId", userId)); object exist = DbHelper.ExecuteScalar(sqlQuery, dbParameters.ToArray()); if (exist != null) { if (BaseSystemInfo.OnLineLimit <= int.Parse(exist.ToString())) { result = true; } } return result; } #endregion } } [![复制代码][copycode.gif]][copycode.gif 1] 3、提供远程访问接口:用户信息的访问;权限信息的访问。访问方式可以是Webservice的方式,封装成一个访问类,方便别人调用。 PermissionService.asmx 权限的WebService中有方法可以获取用户的权限,权限主要注意 1):要判断哪个子系统的权限? 2):每个权限都有一个不重复的编号来识别的。 [![复制代码][copycode.gif]][copycode.gif 1] //----------------------------------------------------------------------- // <copyright file="FriendFansManager.Auto.cs" company="Hairihan"> // Copyright (c) 2013 , All rights reserved. // </copyright> //----------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Services; using DotNet.Business; namespace Friend { /// <remarks> /// PermissionWebService /// 权限检查的WebService /// /// 修改纪录 /// /// 2013.08.17 版本:1.0 JiRiGaLa 更新审核意见。 /// /// 版本:1.0 /// /// <author> /// <name>JiRiGaLa</name> /// <date>2013.08.17</date> /// </author> /// </remarks> [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 PermissionService : System.Web.Services.WebService { // 如果当前用户没登录后台的权限 DotNet.Business.PermissionService permissionService = new DotNet.Business.PermissionService(); // 如果当前用户登录 // DotNet.Utilities.BaseUserInfo userInfo = Utilities.CheckCookie(HttpContext.Current.Request); public PermissionService() { /* if (userInfo != null && !string.IsNullOrEmpty(userInfo.Code)) { if (!string.IsNullOrEmpty(permissionItemCode)) { bool permissionAdmin = permissionService.IsAuthorizedByUser(userInfo, userInfo.Id, permissionItemCode, string.Empty); if (!permissionAdmin) { throw new Exception("没有权限访问。"); } } } else { throw new Exception("没有权限访问。"); } */ } #region public bool IsUserInRole(string systemCode, string userId, string roleCode) /// <summary> /// 用户是否在某个角色里 /// </summary> /// <param name="systemCode">子系统编号</param> /// <param name="userId">用户主键</param> /// <param name="roleCode">角色编号</param> /// <returns>是否在某个角色里</returns> [WebMethod] public bool IsUserInRole(string systemCode, string userId, string roleCode) { // 需要创建个用户对象 DotNet.Utilities.BaseUserInfo userInfo = new DotNet.Utilities.BaseUserInfo(); // 若没指定是哪个子系统,默认就是基础系统 if (string.IsNullOrEmpty(systemCode)) { systemCode = "Base"; } userInfo.SystemCode = systemCode; // 判断用户是否在指定的角色里? BaseUserManager userManager = new BaseUserManager(userInfo); return userManager.IsInRoleByCode(userId, roleCode); } #endregion #region public bool IsAuthorized(string systemCode, string userId, string permissionItemCode) /// <summary> /// 对某个模块、操作是否有权限? /// </summary> /// <param name="systemCode">子系统编号</param> /// <param name="userId">用户主键</param> /// <param name="permissionItemCode">操作权限编号、模块编号</param> /// <returns>是否拥有操作权限</returns> [WebMethod] public bool IsAuthorized(string systemCode, string userId, string permissionItemCode) { bool returnValue = false; // 需要创建个用户对象 DotNet.Utilities.BaseUserInfo userInfo = new DotNet.Utilities.BaseUserInfo(); // 若没指定是哪个子系统,默认就是基础系统 if (string.IsNullOrEmpty(systemCode)) { systemCode = "Base"; } userInfo.SystemCode = systemCode; // 实时从数据库判断权限的调用方法 returnValue = permissionService.IsAuthorizedByUser(userInfo, userId, permissionItemCode, string.Empty); return returnValue; } #endregion #region public bool IsUrlAuthorized(string systemCode, string userId, string url) /// <summary> /// 对某个模块、操作是否有权限? /// </summary> /// <param name="systemCode">子系统编号</param> /// <param name="userId">用户主键</param> /// <param name="url">按网址授权</param> /// <returns>是否拥有操作权限</returns> [WebMethod] public bool IsUrlAuthorized(string systemCode, string userId, string url) { bool returnValue = false; // 需要创建个用户对象 DotNet.Utilities.BaseUserInfo userInfo = new DotNet.Utilities.BaseUserInfo(); // 若没指定是哪个子系统,默认就是基础系统 if (string.IsNullOrEmpty(systemCode)) { systemCode = "Base"; } userInfo.SystemCode = systemCode; // 实时从数据库判断权限的调用方法 returnValue = permissionService.IsUrlAuthorizedByUser(userInfo, userId, url); return returnValue; } #endregion #region public string[] GetUserPermissions(string systemCode, string userId) /// <summary> /// 获取用户的所有权限列表 /// </summary> /// <param name="systemCode">子系统编号</param> /// <param name="userId">用户主键</param> /// <returns>权限编号数组</returns> [WebMethod] public string[] GetUserPermissions(string systemCode, string userId) { List<string> permissions = new List<string>(); // 需要创建个用户对象 DotNet.Utilities.BaseUserInfo userInfo = new DotNet.Utilities.BaseUserInfo(); // 若没指定是哪个子系统,默认就是基础系统 if (string.IsNullOrEmpty(systemCode)) { systemCode = "Base"; } userInfo.SystemCode = systemCode; // 获取用户的所有权限列表 List<BaseModuleEntity> entityList = permissionService.GetModuleListByUser(userInfo, userId); foreach (var entity in entityList) { // 权限编号 // entity.Code; permissions.Add(entity.Code); // 能访问的url列表 // entity.NavigateUrl; // entity.FullName; } return permissions.ToArray(); } #endregion } } [![复制代码][copycode.gif]][copycode.gif 1] A: **SSO服务器端配置说明**: 1: 附加数据库,把sql2008数据库配置好,附加DotNet.CommonV3.9\\DotNet.DataBase\\SQL2008\\UserCenter39 2: 配置 DotNet.Common\\Friend, MVC的单点登录程序,配置数据库连接Web.config中的UserCenterDbConnection的数据库连接。 3: 删除单点登录的SSO,SSOVerify,SSOPermissionService项目,从Web.config中。 进行以上3个步骤,mvc 的 SSO 服务器端就配置好了,在iis里设置好MVC网站就可以了。 B: **SSO 客户端的配置说明**: 1:添加2个dll的引用,DotNet.Business、 DotNet.Utilities,dll在 DotNet.Common\\Friend\\External 目录下。 2:Controller 需要加 \[NeedAuthorize\] 进行单点登录控制, \[NeedUrlAuthorized\]进行ul 权限限制。 3:Web.config 中加 SSO,SSOVerify,SSOPermissionService 的配置。 4:添加 PermissionWebService 引用,就是需要引用 上面里的单点登录 WebService。 5:Global.asax 中需要写一下 Application\_Start() 中的代码复制过去。 目前通用权限管理系统组件完全满足以上需求,方便快速开发各种 .Net 应用软件。 主要需要整理的部分如下列表中的问题 01:MVC 单点登录需求 02:MVC 数据库连接的配置。 03:MVC 用户名密码登录,有错误时需要有错误提示信息。 04:MVC 里保存密码的方式,Cokies 保存测试。 05:MVC cookies 保存的时间长度设置,是否启用cookies。 06:MVC 若有登录自动跳转地址的方式。 07:MVC 用OpenId(Key)登录的方式,登录跳转的优化。 08:MVC 多系统支持单点登录的配置注意事项。 09:MVC 权限判断的例子。 10:MVC URL 权限判断的例子。 11:MVC 退出功能的深入优化,能退出子系统也可以退出主系统。 将权限管理、工作流管理做到我能力的极致,一个人只能做好那么很少的几件事情。 7:需要稳定,2周内就搞定,1周后交付测试,而不是需要研究2个月才能搞定,或者研究2年。 单点登录常见需求: 跨应用、跨域、跨机器的单点登录。 [25205715-37877cdd5c6e4f27a6ebc6b5b4f5a687.png]: /images/20221024/2b63742d1a9247748f70f21a0bbe3523.png [25133720-ceea385b0e694947b90708cc7e1c94a5.png]: /images/20221024/8b1dde24c14d48fe85b829599dc94611.png [25134044-e6aee3d1ad8c45d79679cd96700d5e64.png]: /images/20221024/3e243a0afcfa4eae8bb4af54b024d4b7.png [25134125-f2b4f18127be45fca5f32f34629f5d79.png]: /images/20221024/ac338fdecc8b488c9fcad6129403bb78.png [25134342-93172a634e89470c84b9ce20c7bfb2a0.png]: /images/20221024/7bd9b7ded64f4e1fbbc0f5c109603425.png [25142704-64ade270fcab48c69010a26bf744da8e.png]: /images/20221024/8b1803fbd1a34026b4ef1a05920dadcd.png [25154153-a60700eb2d8f4c6db6645516d4fd0661.png]: /images/20221024/2efce4ed73bf444fbedf7775b1f8f694.png [http_www.sso.com_PermissionService.asmx]: http://www.sso.com/PermissionService.asmx [25154556-5d5e3a10f65d44f78aca500f99b0d45c.png]: /images/20221024/5f0b41ad0a584fcfba4693ffc63c739e.png [25200813-4ec50773e46941a2bfcc3e0ed24f3d28.png]: /images/20221024/d1a733353f9645e6ae84c1577742bb84.png [25205224-74719dcfa881461bbf4bd224ffc2e686.png]: /images/20221024/80bb965ac5d04cc28da4cb701a047bb4.png [25204815-8d9541001b504529a0acb94ff3d7f6b3.png]: /images/20221024/eca38bab7415476481a9a49ee01a93ab.png [25204900-f9fdf11ec5ac47ee9271c042f9055b44.png]: /images/20221024/bbfab62695ce48ac94d03e984427ce77.png [25204427-86c85990fa5d458d96c81944c54ec1ce.png]: /images/20221024/4bf9d6443fbe4edb9bdd28ef6c919f54.png [25134846-066581738b4948b19c113244b19a461a.png]: /images/20221024/688281ae0e71411ca066a602ced54f11.png [24203719-6ff017c9eb4947a0b9757adb32ac4107.png]: /images/20221024/b5bde31101894d16afa198324211ac2c.png [copycode.gif]: http://common.cnblogs.com/images/copycode.gif [copycode.gif 1]: /images/20221024/6ea9c34f1ef24c6999834233015d72e8.png
相关 单点登录 官网 https://apereo.github.io/cas/4.2.x/planning/Architecture.html demo http://www.i 我不是女神ヾ/ 2022年11月03日 10:45/ 0 赞/ 235 阅读
相关 asp.net MVC 中 单点登录 实现sso系统的主要难点: 1:不能直接访问数据库,有安全隐患,而且还容易乱套。 2:多个系统需要进行单点登录,逻辑需要严谨,能支持N多系统、而不只是少数几个系统。 3: 傷城~/ 2022年10月26日 12:51/ 0 赞/ 111 阅读
相关 单点登录 业务需要,正在研究. 基本有以下三种方案 1.集中管理Session. 实现很简单,但缺点是 每次页面刷新都需要访问一次或两次 Session管理服务器, 水深无声/ 2022年09月19日 10:55/ 0 赞/ 237 阅读
相关 单点登录 1:什么事单点登录: SSO英文全称Single Sign On,单点登录。SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。它包括可以将这次主 男娘i/ 2022年07月13日 14:29/ 0 赞/ 228 阅读
相关 单点登录 一、单系统登录机制 1、http无状态协议 web应用采用browser/server架构,http作为通信协议。http是无状态协议,浏览器的每一次请求,服务 港控/mmm°/ 2022年06月11日 00:55/ 0 赞/ 240 阅读
相关 单点登录 项目分为三个模块 server client2 client1 server提供的接口 /user /tol 深藏阁楼爱情的钟/ 2022年05月24日 04:26/ 0 赞/ 275 阅读
相关 单点登录 1.3 CAS服务端部署 Cas服务端其实就是一个war包。 在资源\\cas\\source\\cas-server-4.0.0-release\\cas-serve 梦里梦外;/ 2022年05月16日 08:04/ 0 赞/ 298 阅读
相关 单点登录 初识单点登录 最初接触到单点登录要追溯到3年多以前了,那时候看到的只是passport,当时要做全国所有社区的登录,然后就照着内部文档写了代码,然后就接入了(这里要提一句 谁借莪1个温暖的怀抱¢/ 2022年05月13日 14:04/ 0 赞/ 273 阅读
相关 单点登录 以Cookie作为凭证媒介 最简单的单点登录实现方式,是使用cookie作为媒介,存放用户凭证。 用户登录父应用之后,应用返回一个加密的cookie,当用户访问子应用 £神魔★判官ぃ/ 2022年04月23日 13:18/ 0 赞/ 312 阅读
相关 单点登录 什么是单点登录? 单点登录(Single Sign On)说的简单点就是在一个多系统共存的环境下,用户在一处登录后,就不用在其它系统中登录。也就是用户的一次登录能得到其它所有 布满荆棘的人生/ 2021年11月11日 04:10/ 0 赞/ 455 阅读
还没有评论,来说两句吧...