zoukankan      html  css  js  c++  java
  • 单点登录3

    实现sso系统的主要难点:
    1:不能直接访问数据库,有安全隐患,而且还容易乱套。
    2:多个系统需要进行单点登录,逻辑需要严谨,能支持N多系统、而不只是少数几个系统。
    3:代码不能过于复杂,需要简洁,灵活支持本地部署,单点部署,集群部署,相同的代码可以通过部署配置灵活实现服务段(sso)、本地段(子网站)功能。
    4:多系统的权限也可以灵活判断,不能访问数据库,需要进行远程服务调用,而且还需要对外部系统能提供调用接口。
    5:需要有一定的安全性,能防止注入攻击等等。
    6:权限定义需要非常灵活,可以定义10个权限,也可以定义100个权限,可以根据url进行权限判断,同时可以是n多个业务系统。
    7:需要稳定,2周内就搞定,1周后交付测试,而不是需要研究2个月才能搞定,或者研究2年。
     
    单点登录常见需求:
       跨应用、跨域、跨机器的单点登录。
    1、流程:
       a) 用户直接访问门户url,登录成功后跳转到默认应用的url。
    程序里需要引用2个Dll,通用权限管理系统组件的,这2个dll主要实现权限判断,登录功能等。
    下面是登录页面的位置
    这里是MVC默认的登录页面,
    上图是需要登录的功能定义部分。
    在 MVC 里加上 [NeedAuthorize] 就可以默认要求登录了。不登录不允许访问了。

       b) 用户直接访问应用url,若未登录,跳转到登录页面的url,完成登录后,跳转回应用url。
    上图是跳转的处理,若没指定需要跳转的页面,那就默认回到首页,若有指定的 returnUrl,就跳转回指定的页面里。
     

       c) 用户已经登录,用户直接访问应用的URL,若该用户无权限,跳转到指定的url
    没有访问权限的用户会被重定向到没权限访问的页面
     
    系统中的注意事项,先看下图
    NeedUrlAuthorizedAttribute 是需要进行url验证用的属性,在需要控制的Controller上加上,例如

    判断是否有url权限的调用方法如下:
      [NeedAuthorize]   需要进行登录(这个可以省略)
      [NeedUrlAuthorized] 需要进行Url验证 (首先会要求需要登录)
      [HttpPost]
      public ActionResult User(Friend.Models.User model)
     {
     }
     
    PermissionWebService 是进行权限验证中心远程进行权限判断的WebService,是引用了
    http://www.sso.com/PermissionService.asmx 这个WebService。
    需要在配置文件里进行
    配置
    SystemCode, 主要是来识别,是哪个子系统的权限?因为当前可能10多个网站,那就是有10多个子系统,那就每个子系统需要有一个唯一识别的编号。
     
    那如何设置某个子系统的用的url权限?看下图(用户权限配置参考,子系统设置菜单、菜单编号、菜单url设置):
     
     
    若没登录,就会提示先登录
     
    登录后,若没权限访问这个页面,就会提示没权限访问。
    可以点网页下面的 有情连接进行测试,不用在url里人工输入。
     
       d) 用户已经登录,用户直接访问用户有权限的应用url,通过。
    与上面的需求一致,有权限的自然能通过调用。
    有URL访问权限的,可以显示页面效果如下
     
       E) 跨域的单点登录、权限判断需要注意的配置部分。
    需要在其他需要接入的 其他应用里需要加上这3个配置,认证主服务器上不要进行这个配置,需要删除掉这几行配置信息才可以。

    2、验证码的生成,封装成一个插件,方便各种加强版本的验证需要。
    这个是一个通用的严正码设置与验证码校验的类,可以按自己的需要进行修改。
     
    复制代码

    //-----------------------------------------------------------------
    // 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
        }
    }

    复制代码

     


    3、提供远程访问接口:用户信息的访问;权限信息的访问。访问方式可以是Webservice的方式,封装成一个访问类,方便别人调用。
    PermissionService.asmx 权限的WebService中有方法可以获取用户的权限,权限主要注意
    1):要判断哪个子系统的权限?
    2):每个权限都有一个不重复的编号来识别的。
    复制代码

    //-----------------------------------------------------------------------
    // <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
        }
    }

    复制代码

     

     

    A: SSO服务器端配置说明:

        1: 附加数据库,把sql2008数据库配置好,附加DotNet.CommonV3.9DotNet.DataBaseSQL2008UserCenter39

        2: 配置  DotNet.CommonFriend, 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.CommonFriendExternal 目录下。

       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 退出功能的深入优化,能退出子系统也可以退出主系统。

  • 相关阅读:
    vue Can't resolve 图片
    TP-LINK WR740N中继设置,AP设置,设置后不能上网,亲测有效
    vue VSCode 开发设置(html自动补全、eslint保存时格式化、vetur 格式化html)
    不再手写import
    vscode vuter的快捷键 关键字
    prototype是什么?
    真有效值与有效值概念
    现代文经典
    古文经典
    最后,我想对你说一句:我爱你
  • 原文地址:https://www.cnblogs.com/bosamvs/p/7602110.html
Copyright © 2011-2022 走看看