单点登录的实现

2023-11-17

单点登录一般需要至少两个站、一个登录站、一个接入站(确切的说应该是N个接入站),各个站需要实现的功能如图:

简单说明:登录站提供登录页面和退出功能,并提供用户信息的获取服务。接入站需要提供对应的登录成功回写服务,目的是为了存储本地登录信息,可以使用cookie等存储模式。

主站代码如下:

public class LoginController : Controller
    {
        private UserService UService => new UserService();
        const string SessionKeyForToken = "CurrentUserLoginToken";

        /// <summary>
        /// 登录首页
        /// </summary>
        /// <param name="returnBackPath">返回的页面地址</param>
        /// <param name="callBackPath">回写地址</param>
        /// <returns></returns>
        [HttpGet]
        public ActionResult Index(string returnBackPath, string callBackPath)
        {
            var request = new LoginRequest
            {
                CallBackPath = callBackPath,
                ReTurnBackPath = returnBackPath
            };
            var objToken = Session[SessionKeyForToken];

            //简单检查用户是否已经登录,可以结合数据库或票据之类的进行验证
            if (objToken != null && UService.CheckLoginByToken(objToken.ToString()))
            {
                //已经登录的则跳转到指定的Url
                return RedirectPermanent($"{request.CallBackPath}?token={objToken.ToString()}&returnBackPath={request.ReTurnBackPath}");
            }

            return View(request);
        }

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost]
        public ActionResult Index(LoginRequest request)
        {
            try
            {
                var userModel = UService.GetUserCount(request.LoginName, request.Password);
                if (userModel == null)
                {
                    request.ErrorMsg = "账号密码错误";
                    return View(request);
                }
                var token = Guid.NewGuid().ToString().Replace("-", "");
                CacheHelper.SetCache(token, userModel, DateTime.Now.AddHours(2));//存储用户登录信息
                Session[SessionKeyForToken] = token;//存储用户的token,这边可以自己设置下session的过期时间

                //登录成功跳转到指定的Url
                return RedirectPermanent($"{request.CallBackPath}?token={token}&returnBackPath={request.ReTurnBackPath}");
            }
            catch (Exception ex)
            {
                request.ErrorMsg = ex.Message;
                return View(request);
            }
        }

        /// <summary>
        /// 退出登录
        /// </summary>
        /// <param name="returnBackPath">返回的页面地址</param>
        /// <param name="callBackPath">回写地址</param>
        /// <param name="token">token登录信息</param>
        /// <returns></returns>
        [HttpGet]
        public ActionResult LoginOut(string returnBackPath, string callBackPath, string token)
        {
            var objSession = Session[SessionKeyForToken];//防止token传值出错
            if (objSession != null)
            {
                CacheHelper.RemoveKeyCache(objSession.ToString());//清除用户信息缓存
                Session[SessionKeyForToken] = null;
            }
            else
            {
                CacheHelper.RemoveKeyCache(token);//清除用户信息缓存
            }
            return RedirectToAction("Index", "Login", new { returnBackPath = returnBackPath, callBackPath = callBackPath });
        }
    }

 

@model RightManagerPro.Models.LoginRequest
<head>
    <title>单点登录DEMO</title>
</head>
<body>
    <h2>登录</h2>

    <div>
        @using (Html.BeginForm("Index", "Login", FormMethod.Post))
        {
            <span>用户名:</span>
            @Html.TextBoxFor(t => t.LoginName, new { maxlength = 50 })
            <br />
            <br />
            <span>密码:</span>
            @Html.TextBoxFor(t => t.Password, new { maxlength = 50 })
            <br />
            <br />
            <input type="submit" value="登录" />
            <span style="color:red;">@Model.ErrorMsg</span>

            @Html.HiddenFor(m => m.CallBackPath)
            @Html.HiddenFor(m => m.ReTurnBackPath)
        }
    </div>
</body>

获取用户信息服务代码:

public class AccountController : ApiController
    {
        private UserService UService => new UserService();
        /// <summary>
        /// 获取人员信息
        /// </summary>
        /// <param name="token">token值</param>
        /// <returns></returns>
        [HttpPost]
        public UserModel GetUseInfo(string token)
        {
            return UService.GetUserInfoByToken(token);
        }
    }

 public class UserService
    {
        /// <summary>
        /// 根据Token检测用户的信息
        /// </summary>
        /// <param name="token">token值</param>
        /// <returns></returns>
        public bool CheckLoginByToken(string token)
        {
            if (string.IsNullOrWhiteSpace(token))
            {
                return false;
            }
            //通过Token获取登录实体(账户密码)
            var userModel = CacheHelper.GetCache(token);
            if (userModel == null)
            {
                return false;
            }

            //使用账户密码进行检查登录
            var model = (UserModel)userModel;
            var result = GetUserCount(model.LoginName, model.Password);
            return result != null;
        }

        /// <summary>
        /// 根据Token获取用户的信息
        /// </summary>
        /// <param name="token">token值</param>
        /// <returns></returns>
        public UserModel GetUserInfoByToken(string token)
        {
            if (string.IsNullOrWhiteSpace(token))
            {
                return null;
            }
            //通过Token获取登录实体(账户密码)
            var userModel = CacheHelper.GetCache(token);
            if (userModel == null)
            {
                return null;
            }

            //使用账户密码进行检查登录
            var model = (UserModel)userModel;
            return GetUserCount(model.LoginName, model.Password);
        }

        /// <summary>
        /// 获取用户信息
        /// </summary>
        /// <param name="loginName">用户名</param>
        /// <param name="password">密码</param>
        /// <returns></returns>
        public UserModel GetUserCount(string loginName, string password)
        {
            //TODO-验证用户的账号密码正确性
            return new UserModel
            {
                LoginName = loginName,
                Password = password
            };
        }
    }

其他辅助代码:

 /// <summary>
    /// 登录请求实体
    /// </summary>
    public class LoginRequest
    {
        /// <summary>
        /// 用户名
        /// </summary>
        public string LoginName { get; set; } = string.Empty;

        /// <summary>
        /// 密码
        /// </summary>
        public string Password { get; set; } = string.Empty;

        /// <summary>
        /// 回调地址授权Token
        /// </summary>
        public string CallBackPath { get; set; } = string.Empty;

        /// <summary>
        /// 返回的页面地址
        /// </summary>
        public string ReTurnBackPath { get; set; } = string.Empty;

        /// <summary>
        /// 错误提示信息
        /// </summary>
        public string ErrorMsg { get; set; } = string.Empty;
    }

 public class UserModel
    {
        /// <summary>
        /// 用户名
        /// </summary>
        public string LoginName { set; get; }

        /// <summary>
        /// 密码
        /// </summary>
        public string Password { set; get; }
    }

接入站代码:

  public class OauthController : Controller
    {
        /// <summary>
        /// 授权登录回调方法
        /// </summary>
        /// <param name="token">token</param>
        /// <param name="returnBackPath">返回页面</param>
        /// <returns></returns>
        public ActionResult AuthCallback(string token, string returnBackPath)
        {
            var errorInfos = string.Empty;
            try
            {
                var cookie = new HttpCookie(Constant.AccessToken, token)
                {
                    //cookie过期时间固定设置为2小时,与token过期时间一致
                    Expires = DateTime.Now.AddHours(2),
                    Path = Constant.WebRootPath
                };
                Response.AppendCookie(cookie);
                if (string.IsNullOrEmpty(returnBackPath))
                {
                    return RedirectToAction("Index", "Home");
                }
                return RedirectPermanent(returnBackPath);
            }
            catch (Exception ex)
            {
                errorInfos += ";发生异常:" + ex.Message + ex.StackTrace;
            }
            ViewBag.ErrorInfo = errorInfos;
            return View("Error", errorInfos);
        }

        public ActionResult Error(string errorInfos)
        {
            ViewBag.ErrorInfo = errorInfos;
            return View();
        }
    }
/// <summary>
        /// 首页
        /// </summary>
        /// <returns></returns>
        public ActionResult Index()
        {
            var model = new UserModel { LoginName = "未登录,请登录" };
            var token = HttpContext.Request.Cookies[Constant.AccessToken];
            if (token == null || string.IsNullOrEmpty(token.Value))//没有登录
            {
                return View(model);
            }
            model = OauthService.GetUserInfo(token.Value);
            if (model == null)
            {
                return View(new UserModel { LoginName = "未登录,请登录" });
            }
            return View(model);
        }

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public ActionResult Login()
        {
            Response.Redirect(OauthService.GenerateLoginUrl(Constant.LoginUrl));
            return View();
        }

        /// <summary>
        /// 退出登录
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public ActionResult LoginOut()
        {
            var tokenKey = string.Empty;
            var url = string.Empty;
            var cookies = HttpContext.Request.Cookies[Constant.AccessToken];
            if (cookies != null && !string.IsNullOrEmpty(cookies.Value))
            {
                tokenKey = cookies.Value;
                cookies.Expires = DateTime.Now.AddDays(-1);
                cookies.Path = Constant.WebRootPath;
                HttpContext.Response.Cookies.Add(cookies);
                HttpContext.Request.Cookies.Remove(Constant.AccessToken);
            }
            Response.Redirect(OauthService.GetLoginOutUrl(tokenKey));
            return View();
        }

网站部署:

【实现的效果如下图:】

非登录状态——

登录——

登录之后——

完整的代码Demo下载:

登录主站代码:https://pan.baidu.com/s/1dpqAtzRTHq0-k_S_GBEoiA  09lw

接入站代码:https://pan.baidu.com/s/1ZVnGhKIG5T8LF9b0hUjbWw  nnbn

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

单点登录的实现 的相关文章

  • lua c++中的一种回调解决方法

    见很多人发问cocos2dx 3 版本 lua 函数回调问题 我在项目中是这样解决的 因为我是使用了cocos 带有的 lua 绑定脚本 python写的 cocos2d x tools tolua genbindings py 在生成绑定

随机推荐

  • mac .ssh文件位置

    1 Finder gt 前往文件夹 gt 输入 ssh 2 打开终端 输入cd ssh cd ssh
  • vue组件库的开发流程

    欢迎点击领取 前端面试题进阶指南 前端登顶之巅 最全面的前端知识点梳理总结 开发流程 1 创建项目 vue cli 公司现有架构 2 调整项目静态目录结构 3 使用webpack相关库模式打包编译 4 使用npm或者公司源地址发布到你需要的
  • 向List Control中添加ACCESS数据内容

    转 给List Control 添加变量tt 加入引入ADO使用智能指针 import c program files common files system ado msado15 dll no namespace rename EOF
  • MySQL - 索引的隐藏和删除

    隐藏索引 MySQL 8开始支持隐藏索引 隐藏索引提供了更人性化的数据库操作 隐藏索引 顾名思义 让索引暂时不可见 不会被优化器使用 默认情况下索引是可见的 隐藏索引可以用来测试索引的性能 验证索引的必要性时不需要删除索引 可以先将索引隐藏
  • 【qt应用软件Focus Note++】

    本专栏介绍了使用Qt开发的一些小型桌面软件 其中包括软件功能介绍 软件截图 主要代码等内容 此外 本专栏还提供完整的软件源码和安装包供有需要的同学下载 我的目标是开发一些简洁美观且实用的客户端小软件 如果能够为大家提供有用的软件或对学习有益
  • 赶紧来修炼内功~字符串函数详解大全(一)

    目录 1 strlen 重点 模拟实现 法一 法二 法三 2 strcpy 重点 模拟实现 3 strcat 重点 模拟实现 4 strcmp 重点 模拟实现 1 strlen strlen函数是用来计算字符串长度的 重点 字符串以 0 作
  • Ipsec phase1 and phase2

    终于明白是怎么回事了 困扰我好多天了 网上的资料鱼龙混杂 直到这位大虾的出现 第一阶段 有主模式和积极模式2种 只有remote vpn和Easy vpn是积极模式的 其他都是用主模式来协商的 让IKE对等体彼此验证对方并确定会话密钥 这个
  • 初探oVirt-体验

    日期 2015 9 2 2016 11 15 time 16 40 主机 node72 node73 node86 node93 目的 初探oVirt 体验 操作内容 一 基础环境 1 官方建议 1 oVirt Engine 需求 最低 双
  • 为OkGo网络请求增加自定义log功能

    OkGo是基于Okhttp3的封装 所以只需要增加自定义拦截器就可以实现自定义log OkGo有一个默认的log拦截器HttpLoggingInterceptor 如果没有特别需求则无需自定义 第一步自定义拦截器 参考OkGo中的拦截器实现
  • ctfshow-web4

    0x00 前言 CTF 加解密合集 CTF Web合集 0x01 题目 0x02 Write Up 和web3是相同的内容 这里可以通过任意文件读取的方式来进行利用 这里根据返回包知道是nginx 默认nginx日志是 var log ng
  • 如何批量上传Maven仓库jar包到Nexus3.x私服

    一 手动mvn命令上传单个Jar mvn deploy deploy file DgroupId com oracle DartifactId ojdbc6 Dversion 10 2 0 1 0 Dpackaging jar Dfile
  • 一、使用interrupt()中断线程

    当一个线程运行时 另一个线程可以调用对应的Thread对象的interrupt 方法来中断它 该方法只是在目标线程中设置一个标志 表示它已经被中断 并立即返回 这里需要注意的是 如果只是单纯的调用interrupt 方法 线程并没有实际被中
  • 执行pod setup 报错error: RPC failed; curl 18 transfer closed with outstanding read data remainin

    执行pod setup 报错 error RPC failed curl 18 transfer closed with outstanding read data remaining fatal the remote end hung u
  • 结构化稀疏----Learning with Structured Sparsity(学习与结构化稀疏)

    Structured Sparsity是在标准稀疏算法基础上 修改惩罚项而成 约束项为图像先验信息 迫使学习特征按照一定规则排列 行成有结构的字典 Standard sparsity Group Sparsity Group Sparsit
  • dfs全排列总结

    17 Letter Combinations of a Phone Number Medium 12161744Add to ListShare Given a string containing digits from 2 9 inclu
  • javascript代码混淆的原理

    如何对JavaScript进行保护 代码压缩 去除空格 换行等 代码加密 eval eval可以将其中的参数按照JavaScript的的语法进行解析并执行 其实就是将JavaScript的代码变成了eval的参数其中的一些字符会被按照特定的
  • Realtime_Multi-Person_Pose_Estimation demo.ipynb代码注释

    该部分可以帮助很好的理解论文的实现部分 源码地址 https github com ZheC Realtime Multi Person Pose Estimation 论文地址 https arxiv org abs 1611 08050
  • CVPR 2022

    点击下方卡片 关注 CVer 公众号 AI CV重磅干货 第一时间送达 作者 弃之 已授权转载 源 知乎 编辑 CVer https zhuanlan zhihu com p 478079763 PR一下我们在CVPR 2022上的pape
  • 12年经验资深产品经理领你从“产品小白”走向“产品大牛”

    当今社会 智能音箱 智能机器人 智能可穿戴设备等人工智能产品已经开始逐渐普及 而人工智能产品经理却少之又少 查看智联 拉勾 猎聘等多个招聘网站中企业招聘人工智能产品经理的岗位要求 发现不同公司在招聘人工智能产品经理时的标准都不一样 有些偏重
  • 单点登录的实现

    单点登录一般需要至少两个站 一个登录站 一个接入站 确切的说应该是N个接入站 各个站需要实现的功能如图 简单说明 登录站提供登录页面和退出功能 并提供用户信息的获取服务 接入站需要提供对应的登录成功回写服务 目的是为了存储本地登录信息 可以