• SSO


    进公司以来, 所做的产品中, 下面的子系统就没有少于10个的, 其中有的是.net做的, 有的是java做的, 还有安卓端, ios端. 那么这么多子系统, 我可能需要访问其中的多个(同一平台), 我是否需要登录多次来操作呢? 这样是不是太不方便了. 在我们登录qq之后, 进入qq邮箱, 也并没有让我们多登录一次, 而是直接进去了. 那么在我们的这些系统中, 怎么来实现这种功能呢? 

    到这里, 就引出今天的主题 - SSO 单点登录. 在我们登录系统A之后, 去访问系统B, 此时并不需要再去登陆一次了. 这里有一个前提, 就是不论系统A还是系统B, 用的都是同一个账户和密码. 如果他们之间的用户名和密码不相同, 就麻烦很多了.

    在网上搜到的单点登录解决方案, 比较多的是CAS, 耶鲁大学弄得一个单点登录解决方案。当然,在此篇,并不会介绍到CAS,只是通过一个小例子,来看看轮廓而已。

    一、效果展示 

    在这里,我有三个网站, 当我在Server这个网站登录之后,ClientA,ClientB我直接输入backUrl后面的地址, 看看是否要让我登录。

    输入之后, 让我直接进去了, 而没有让我再次登录。

    当我在HomeA页面登出之后, 再去刷新其他的两个页面来看。

    其他两个页面,也被迫登出了。

    从效果上看, 是不是一个系统登录, 多个系统可以免登录了, 一处登出, 多个系统都被登出。 这就是一个单点登录的效果了。

     

     二、关键代码

    服务器登录部分:

    [NoLogin]
    public ActionResult LoginCheck(string userName, string userPwd)
    {
        if (userName == "admin" && userPwd == "123456")
        {
            User user = new User { Guid = Guid.NewGuid().ToString(), Name = "admin", Pwd = "123456" };
    
            var newCookie = new HttpCookie("userCode", user.Guid);
            newCookie.Expires = DateTime.Now.AddDays(1);
            Response.Cookies.Add(newCookie);
    
            RedisCache.Instance.Set(user.Guid, user, TimeSpan.FromMinutes(1));
    
            return Json(new { status = "ok", guid = user.Guid });
        }
        return Json(new { status = "notMatch" });
    }

    这里的NoLogin就是一个空的特性,里面啥都没有,可以放在类和方法上,用来判断是否不需要登录就可以直接访问页面。

    当验证成功登录后, 将生成一个凭据Guid, 一会用户手持这个凭据来系统验证, 我这边就只看redis缓存中是否有这个缓存存在, 有则表示已经登录。并没有做更多的验证了。

    我这里的redis是部署在ubuntu虚拟机上面的, redis对windows的支持并不是很好, 但是也能找到windows的版本, 如果可能的话, 我还是建议使用 linux 部署 redis。

    客户端验证部分:

    public class SSOClientAttribute : AuthorizeAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            //判断请求的方法或者控制器上, 有没有免登陆特性
            if (filterContext.ActionDescriptor.IsDefined(typeof(NoLoginAttribute), false)
                || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(NoLoginAttribute), false))
            {
                return;
            }
    
            //需要登陆的方法, 继续验证
            base.OnAuthorization(filterContext);
        }
    
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            HttpCookie cookie = httpContext.Request.Cookies["userCode"];
            if (cookie == null || string.IsNullOrEmpty(cookie.Value))
                return false;
    
            var user = RedisCache.Instance.GetOrDefault<User>(cookie.Value);
    
            if (user != null)
            {
                cookie.Expires = DateTime.Now.AddDays(1);
                httpContext.Response.SetCookie(cookie);
                RedisCache.Instance.Set(user.Guid, user, TimeSpan.FromMinutes(10));
                return true;
            }
    
            return false;
        }
       
        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            string loginUrl = ConfigurationManager.AppSettings["LoginUrl"];
            string Url = filterContext.RequestContext.HttpContext.Request.Url.AbsoluteUri;
            loginUrl += "?backUrl=" + Url;
            filterContext.HttpContext.Response.Redirect(loginUrl, true);
        }
    }

    登出部分就简单了, 只要清除cookie和redis缓存就行了。代码就不贴了。

    三、结束语

    CAS的单点登录比这个复杂多了, 这里只是我自己弄得一个小Demo,只是对单点登录的一个初步认识,后面有机会的话, 希望我会把Cas的搭建、使用方法或者解析贴出来。

     

     参考:

      蔡的mysso例子(以前看过他的例子,我写的更简单点,能实现效果就成了)

  • 相关阅读:
    java.io.FileNotFoundException: D:workspacegbrmWebRoot空缺职位列表20140414093026.xls (系统找不到指定的路径。)
    select * from (select t.*,rownum as rowno from (select * from j_kqzw where 1=1 and DEADLINE >='2013-04-14' and DEADLINE <='2014-04-14' ) t)where rown
    hibernate的映射文件字段长度和数据库里面的字段长度
    八门神器
    计算机
    c语言
    捕鱼达人
    桂林力港网络科技有限公司
    cocos2d-x
    3gp 编辑
  • 原文地址:https://www.cnblogs.com/elvinle/p/6471967.html
Copyright © 2020-2023  润新知