• .NET基于Redis缓存实现单点登录SSO的解决方案


    一、基本概念

    最近公司的多个业务系统要统一整合使用同一个登录,这就是我们耳熟能详的单点登录,现在就NET基于Redis缓存实现单点登录做一个简单的分享。

    单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

    普通的登录是写入session,每次获取session看看是否有登录就可记录用户的登录状态。

    同理多个站点用一个凭证,可以用分布式session,我们可以用redis实现分布式session,来实现一个简单的统一登录demo

    我们在本地IIS建立三个站点

    http://www.a.com  登录验证的站点

    http://test1.a.com 站点1

    http://test2.a.com 站点2

    修改host文件C:WindowsSystem32driversetc下

    127.0.0.1 www.a.com

    127.0.0.1 test1.a.com

    127.0.0.1 test2.a.com

    127.0.0.1 sso.a.com

    具体实现原理,当用户第一次访问应用系统test1的时候,因为还没有登录,会被引导到认证系统中进行登录;根据用户提供的登录信息,认证系统进行身份校验,如果通过校验,应该返回给用户一个认证的凭据--ticket;用户再访问别的应用的时候就会将这个ticket带上,作为自己认证的凭据,应用系统接受到请求之后会把ticket送到认证系统进行校验,检查ticket的合法性。如果通过校验,用户就可以在不用再次登录的情况下访问应用系统test2和应用系统test3了。

    项目结构

    二、代码实现

    sso.a.com登录验证站点

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="ADJ.SSO.Web.Index" %>
    
    <!DOCTYPE html>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>SSO demo</title>
    </head>
    <body>
        <form id="form1" runat="server">
               用  户:<input id="txtUserName" type="text" name="userName" /><br /><br />
               密  码:<input type="password" name="passWord" /><br /><br />
                <input type="submit" value="登录" /><br /><br />
             
                <span style="color: red; margin-top: 20px;"><%=StrTip %></span>
        </form>
    
    </body>
    </html>

    代码:

     public partial class Index : System.Web.UI.Page
        {
            //定义属性
            public string StrTip { get; set; }
            public string UserName { get; set; }
            public string PassWork { get; set; }
            protected void Page_Load(object sender, EventArgs e)
            {
                if (Page.IsPostBack)
                {
                    ValidateUser();
                }
            }
    
            //登录验证
            private void ValidateUser()
            {
                var username = Request.Form["userName"];
                if (username.Equals(""))
                {
                    StrTip = "请输入用户名";
                    return;
                }
                var password = Request.Form["passWord"];
                if (password.Equals(""))
                {
                    StrTip = "请输入密码";
                    return;
                }
    
                //模拟登录
                if (username == "admin" && password == "admin")
                {
                    UserInfo userInfo=new UserInfo()
                    {
                        UserName = "admin",PassWord = "admin",Info ="登录模拟" 
                    };
    
                    //生成token
                    var token = Guid.NewGuid().ToString();
                    //写入token
                    Common.Common.AddCookie("token", token, Int32.Parse(ConfigurationManager.AppSettings["Timeout"]));
                    //写入凭证
                    RedisClient client = new RedisClient(ConfigurationManager.AppSettings["RedisServer"], 6379);
                    client.Set<UserInfo>(token, userInfo);
    
    
                    //跳转回分站
                    if (Request.QueryString["backurl"] != null)
                    {
                        Response.Redirect(Request.QueryString["backurl"].Decrypt(), false);
                    }
                    else
                    {
                        Response.Redirect(ConfigurationManager.AppSettings["DefaultUrl"], false);
                    }
                }
                else
                {
                    StrTip = "用户名或密码有误!";
                    return; 
                }
    
            }
        }

    配置文件:

    <appSettings>
      <!--sso验证-->
      <add key="UserAuthUrl" value="http://sso.a.com/"/>
      <!--redis服务器-->
      <add key="RedisServer" value="192.168.10.121"/>
      <!--过期时间-->
      <add key="Timeout" value="30"/>
      <!--默认跳转站点-->
      <add key="DefaultUrl" value="http://test1.a.com/"/>
    </appSettings>

    注销代码:

    var tokenValue = Common.Common.GetCookie("token");
    Common.Common.AddCookie("token",tokenValue,-1);
    HttpContext.Current.Response.Redirect(ConfigurationManager.AppSettings["DefaultUrl"]);

    其他站点验证是否登录的代码:PassportService

    public class PassportService
        {
            public static string TokenReplace()
            {
                string strHost = HttpContext.Current.Request.Url.Host;
                string strPort = HttpContext.Current.Request.Url.Port.ToString();
                string url = String.Format("http://{0}:{1}{2}", strHost, strPort, HttpContext.Current.Request.RawUrl);
                url = Regex.Replace(url, @"(?|&)Token=.*", "", RegexOptions.IgnoreCase);
                return ConfigurationManager.AppSettings["UserAuthUrl"] + "?backurl=" + url.Encrypt();
            }
            public void Run()
            {
                var token = Common.Common.GetCookie("token");
    
                RedisClient client = new RedisClient(ConfigurationManager.AppSettings["RedisServer"], 6379);
    
                UserInfo userInfo = client.Get<UserInfo>(token);
                if (userInfo == null)
                {                                                                                                                        
                    Common.Common.AddCookie("token", token, -1);
                    //令牌错误,重新登录
                    HttpContext.Current.Response.Redirect(TokenReplace(), false);
                }
                else
                {
                    Common.Common.AddCookie("token", token, Int32.Parse(ConfigurationManager.AppSettings["Timeout"]));
                }
            }
    
            public UserInfo GetUserInfo()
            {
                var token = Common.Common.GetCookie("token");
                RedisClient client = new RedisClient(ConfigurationManager.AppSettings["RedisServer"], 6379);
                return client.Get<UserInfo>(token) ?? new UserInfo();
            }
    
        }

    三、最后看下效果图

    四、代码下载

    这里只做了一个简单的实现,提供了一个简单的思路,具体用的时候可以继续完善。

    代码下载:

    http://pan.baidu.com/s/1pK9U8Oj

    五、加关注

    如果本文对你有帮助,请点击右下角【好文要顶】和【关注我

  • 相关阅读:
    MAC 使用git时 不自动补全
    MAC 下 安装redis 并配置 php redis 扩展
    PHP日志 LOG4PHP 的配置与使用
    PHP数组 转 对象/对象 转 数组
    将数组打印到txt文件中
    Yii2控制器 返回 json 格式数据
    控制流输出26大小写英文字母
    员工领导部门关系类
    重写父类
    递归(recursion)
  • 原文地址:https://www.cnblogs.com/yinrq/p/5276628.html
Copyright © 2020-2023  润新知