您的位置:首页 > 教程 > ASP.NET > 基于ASP.NET实现单点登录(SSO)的示例代码

基于ASP.NET实现单点登录(SSO)的示例代码

2022-05-10 13:01:41 来源:易采站长站 作者:

基于ASP.NET实现单点登录(SSO)的示例代码

目录
背景逻辑分析代码实现Service总结

背景

先上个图,看一下效果:

SSO英文全称Single Sign On(单点登录)。SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。它包括可以将这次主要的登录映射到其他应用中用于同一个用户的登录的机制。

它是目前比较流行的企业业务整合的解决方案之一。(本段内容来自百度百科)   话不多说,开撸!

逻辑分析

Client1:用户A在电脑1上登录管理员账号

Service:验证用户A登陆成功生成Admin账号的Token令牌,分别存储电脑1的cookie中和服务器的全局变量中(可以是session,缓存,全局变量,数据库)

Client2:用户B在电脑2上登录管理员账号

Service:验证用户B登陆成功重新生成Admin账号的Token令牌,分别存储电脑2的cookie中和服务器的全局变量中(可以是session,缓存,全局变量,数据库)

Client1:触发验证:

1,判断服务器全局变量是否过期,提示:身份信息过期,请重新登录。

2,判断客户端的cookie是否过期,提示:长时间未登录,已下线。

3,判断电脑1上的cookie与服务器全局变量相比是否一致。提示:此用户已在别处登陆!你被强制下线!

代码实现

Service

1,创建一个服务器校验登录类,代码如下

using Coldairarrow.Business;
using Coldairarrow.Util;
using System;
using System.Text;
using System.Web.Mvc;

namespace Coldairarrow.Web
{
    /// <summary>
    /// 校验登录
    /// </summary>
    public class CheckLoginAttribute : FilterAttribute, IActionFilter
    {
        public IOperator _operator { get; set; }
        public ILogger _logger { get; set; }

        /// <summary>
        /// Action执行之前执行
        /// </summary>
        /// <param name="filterContext">过滤器上下文</param>
        public void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var request = filterContext.RequestContext.HttpContext.Request;
            try
            {
                //若为本地测试,则不需要登录
                if (GlobalSwitch.RunModel == RunModel.LocalTest)
                {
                    return;
                }

                //判断是否需要登录
                bool needLogin = !filterContext.ContainsAttribute<IgnoreLoginAttribute>();

                //获取session里面的用户id
                var uid = SessionHelper.Session["UserId"]?.ToString();

                if (needLogin)
                {
                    if (string.IsNullOrEmpty(uid))
                    {

                        //转到登录
                        RedirectToLogin();

                    }
                    else
                    {
                        var Cguid = filterContext.HttpContext.Request.Cookies["CToken"].Value?.ToString();
                        var Sguid = CacheHelper.Cache.GetCache(uid + "_SToken")?.ToString();



                        //判断是否过期
                        if (string.IsNullOrEmpty(Cguid) || string.IsNullOrEmpty(Sguid))
                        {
                            //  过期  转到登录
                            ReturnLogin("身份信息以失效,请重新登陆!");
                            SessionHelper.Session["UserId"] = "";
                        }
                        else
                        {
                            //判断用户是否重复登陆
                            if (Sguid != Cguid)
                            {
                                //  过期  转到登录
                                ReturnLogin("此用户已在别处登陆!你被强制下线!");
                                SessionHelper.Session["UserId"] = "";
                                //message = "已登陆";
                            }
                        }

                    }


                }







                //if (needLogin && !_operator.Logged())
                //{                //转到登录
                //    RedirectToLogin();
                //}
                //else
                //{


                //    string Id = _operator.UserId;
                //    _operator.Login(Id);
                //    return;
                //}
            }
            catch (Exception ex)
            {
                _logger.Error(ex);
                RedirectToLogin();
            }

            void RedirectToLogin()
            {
                if (request.IsAjaxRequest())
                {
                    filterContext.Result = new ContentResult
                    {
                        Content = new AjaxResult { Success = false, ErrorCode = 1, Msg = "未登录" }.ToJson(),
                        ContentEncoding = Encoding.UTF8,
                        ContentType = "application/json"
                    };
                }
                else
                {
                    UrlHelper urlHelper = new UrlHelper(filterContext.RequestContext);
                    string loginUrl = urlHelper.Content("~/Home/Login");
                    string script = $@"    
            <html>
                <script>
                    top.location.href = '{loginUrl}';
                </script>
            </html>
            ";
                    filterContext.Result = new ContentResult { Content = script, ContentType = "text/html", ContentEncoding = Encoding.UTF8 };
                }
            }

            void ReturnLogin(string msg)
            {
                UrlHelper urlHelper = new UrlHelper(filterContext.RequestContext);
                string loginUrl = urlHelper.Content("~/Home/Login");
                string script = $@"    
            <html>
                <script>
                    alert('{msg}');
                    top.location.href = '{loginUrl}';
                </script>
            </html>
            ";
                filterContext.Result = new ContentResult { Content = script, ContentType = "text/html", ContentEncoding = Encoding.UTF8 };
            }
        }

        /// <summary>
        /// Action执行完毕之后执行
        /// </summary>
        /// <param name="filterContext"></param>
        public void OnActionExecuted(ActionExecutedContext filterContext)
        {

        }
    }
}

2,创建一个mvc基控制器继承Controller并且引用特性【CheckLogin】

3,业务控制器继承BaseMvcController,并编写登录代码。登陆成功后调用login方法,代码如下:

/// <summary>
        /// 登录
        /// </summary>
        /// <param name="userId">用户逻辑主键Id</param>
        public void Login(string userId)
        {
            //保存登陆成功的令牌
            string Guid_str = "";
            //分配一个唯一标识符
            Guid_str = GuidHelper.GuidTo16String();
            HttpContext.Current.Response.Cookies["CToken"].Value = Guid_str;
            //给系统变量存储一个值,Uid代表哪个用户,GUID则是唯一标识符
            CacheHelper.Cache.SetCache(userId + "_SToken", Guid_str, new TimeSpan(0, 0, 30, 0, 0), ExpireType.Absolute);
            SessionHelper.Session["UserId"] = userId;
        }

4,这个时候基本就结束了,还需要增加一个忽略验证的类,这个特性加在登录页面。意思是登录页面不需要触发验证;

5,服务器验证的核心代码有点不优雅,不过实现逻辑了。有问题可以评论区沟通一下。本人用的是将token分别存储在服务器缓存+客户端cookie完成  ,大家服务器上可以用session,缓存,全局变量,数据库等任意方式实现;

总结

当用户没有重复登陆时,系统分配一个guid给用户,并记录用户id和对应的guid,这个用户在线时系统变量存储的用户id以及对应的guid值是不会变的,这时候有另外一个人用相同的账号登陆时,会改变系统变量中用户id对应的guid。

这时候服务器就判断出系统变量存储的guid与用户cookie存储的guid不同时,就会强制用户下线。

这个可以升级为指定N台设备登录,并且可以增加socket的方式通知其他电脑下线。由于业务不需要,就没有增加即时通讯。

到此这篇关于基于ASP.NET实现单点登录(SSO)的示例代码的文章就介绍到这了,更多相关ASP.NET单点登录内容请搜索易采站长站以前的文章或继续浏览下面的相关文章希望大家以后多多支持易采站长站!

如有侵权,请联系QQ:279390809 电话:15144810328

相关文章

  • [Asp.Net Core] 浅谈Blazor Server Side

    [Asp.Net Core] 浅谈Blazor Server Side

    在2016年, 本人就开始了一个内部项目, 其特点就是用C#构建DOM树, 然后把DOM同步到浏览器中显示. 并且在一些小工程中使用. 3年下来, 效果很不错, 但因为是使用C#来构建控件树, 在没有特定
    2020-07-01
  • asp.net生成Excel并导出下载五种实现方法

    asp.net生成Excel并导出下载五种实现方法

    方法一 通过GridView(简评:方法比较简单,但是只适合生成格式简单的Excel,且无法保留VBA代码),页面无刷新 aspx.cs部分 代码如下: using System; using System.Collections; using System.Configuration; usi
    2019-05-16
  • Asp.Net Core用NLog记录日志操作方法

    Asp.Net Core用NLog记录日志操作方法

    需求 1.日志自动写入到数据库、写入到文件 2.appsettings.json数据库连接更改后,不需要去改NLog中的连接地址,启动网站或项目时自动检测变动然后去更改,以appsettings.json为准,保持同步
    2019-11-19
  • 使用vs2019加.net core 对WeiApi的创建过程详解

    使用vs2019加.net core 对WeiApi的创建过程详解

    vs2019创建webapi 1.创建新的项目 2.选择.NET CORE的ASP .NET CORE WEB应用程序 3.定义项目名称和存放地点 4.选择API创建项目 5.删除原本的无用的类 6.添加新的方法类 7.设置路由 using Microsoft.AspNe
    2020-07-03
  • 教你Asp.net下使用mysql数据库的步骤

    教你Asp.net下使用mysql数据库的步骤

    1. 首先需要安装mysql, 易采站长站下载地址: //www.jb51.net/softs/2193.html 或者去mysql.com官网都可以,一路next,安装好后,有个简单配置,提示有个设置登录密码和服务名称, 默认localhost,用
    2019-05-16
  • [Asp.Net Core]用Blazor Server Side实现图片验证码

    [Asp.Net Core]用Blazor Server Side实现图片验证码

    关于Blazor 由于在国内, Blazor一点都不普及, 在阅读此文前, 建议读者先翻看我之前写的随笔, 了解Blazor Server Side的特点. 在一段时间内, 我会写一些解说分析型的 "为什么选择 Blazor Server
    2020-07-01
  • 详解ASP.NET Razor 语法

    详解ASP.NET Razor 语法

    Razor 同时支持 C# (C sharp) 和 VB (Visual Basic)。 主要的 Razor C# 语法规则 Razor 代码块包含在 @{ ... } 中 内联表达式(变量和函数)以 @ 开头 代码语句用分号结束 变量使用 var 关键字声明 字符
    2020-07-07
  • .Net Core中使用ExceptionFilter过滤器的方法

    .Net Core中使用ExceptionFilter过滤器的方法

    .Net Core中有各种Filter,分别是AuthorizationFilter、ResourceFilter、ExceptionFilter、ActionFilter、ResultFilter。可以把他们看作是.Net Core自带的AOP的扩展封装。 今天来看其中的一种:ExceptionFilter(用于
    2020-03-03